Update C sources

This commit is contained in:
Milan Nikolic 2020-05-04 18:19:50 +02:00
parent efd3445362
commit 7ab77a4730
No known key found for this signature in database
GPG key ID: 9229D0EAA3AA4E75
103 changed files with 25993 additions and 13806 deletions

View file

@ -28,12 +28,12 @@ func main() {
}
if rl.IsKeyPressed(rl.KeyEnter) {
rl.StorageSaveValue(storageScore, score)
rl.StorageSaveValue(storageHiscore, hiscore)
rl.SaveStorageValue(storageScore, score)
rl.SaveStorageValue(storageHiscore, hiscore)
} else if rl.IsKeyPressed(rl.KeySpace) {
// NOTE: If requested position could not be found, value 0 is returned
score = rl.StorageLoadValue(storageScore)
hiscore = rl.StorageLoadValue(storageHiscore)
score = rl.LoadStorageValue(storageScore)
hiscore = rl.LoadStorageValue(storageHiscore)
}
framesCounter++

View file

@ -22,7 +22,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2015-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2015-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -133,7 +133,7 @@ void SetCameraMoveControls(int frontKey, int backKey,
#if defined(CAMERA_IMPLEMENTATION)
#include <math.h> // Required for: sqrt(), sinf(), cosf()
#include <math.h> // Required for: sinf(), cosf(), sqrtf()
#ifndef PI
#define PI 3.14159265358979323846
@ -167,8 +167,8 @@ void SetCameraMoveControls(int frontKey, int backKey,
// FIRST_PERSON
//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f
#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f
#define CAMERA_FIRST_PERSON_MIN_CLAMP 85.0f
#define CAMERA_FIRST_PERSON_MAX_CLAMP -85.0f
#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f
#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f
#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0f
#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f
@ -197,26 +197,38 @@ typedef enum {
MOVE_DOWN
} CameraMove;
// Camera global state context data
typedef struct {
int mode; // Current camera mode
float targetDistance; // Camera distance from position to target
float playerEyesPosition; // Default player eyes position from ground (in meters)
Vector2 angle; // Camera angle in plane XZ
int moveControl[6];
int smoothZoomControl; // raylib: KEY_LEFT_CONTROL
int altControl; // raylib: KEY_LEFT_ALT
int panControl; // raylib: MOUSE_MIDDLE_BUTTON
} CameraData;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static Vector2 cameraAngle = { 0.0f, 0.0f }; // Camera angle in plane XZ
static float cameraTargetDistance = 0.0f; // Camera distance from position to target
static float playerEyesPosition = 1.85f; // Default player eyes position from ground (in meters)
static int cameraMoveControl[6] = { 'W', 'S', 'D', 'A', 'E', 'Q' };
static int cameraPanControlKey = 2; // raylib: MOUSE_MIDDLE_BUTTON
static int cameraAltControlKey = 342; // raylib: KEY_LEFT_ALT
static int cameraSmoothZoomControlKey = 341; // raylib: KEY_LEFT_CONTROL
static int cameraMode = CAMERA_CUSTOM; // Current camera mode
static CameraData CAMERA = { // Global CAMERA state context
.mode = 0,
.targetDistance = 0,
.playerEyesPosition = 1.85f,
.angle = { 0 },
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
.smoothZoomControl = 341,
.altControl = 342,
.panControl = 2
};
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
#if defined(CAMERA_STANDALONE)
// NOTE: Camera controls depend on some raylib input functions
// TODO: Set your own input functions (used in UpdateCamera())
static void EnableCursor() {} // Unlock cursor
static void DisableCursor() {} // Lock cursor
@ -241,19 +253,19 @@ void SetCameraMode(Camera camera, int mode)
float dy = v2.y - v1.y;
float dz = v2.z - v1.z;
cameraTargetDistance = sqrtf(dx*dx + dy*dy + dz*dz);
CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz);
// Camera angle calculation
cameraAngle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
cameraAngle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW)
CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW)
playerEyesPosition = camera.position.y;
CAMERA.playerEyesPosition = camera.position.y;
// Lock cursor for first person and third person cameras
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
else EnableCursor();
cameraMode = mode;
CAMERA.mode = mode;
}
// Update camera depending on selected mode
@ -261,13 +273,13 @@ void SetCameraMode(Camera camera, int mode)
// System: EnableCursor(), DisableCursor()
// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
// Keys: IsKeyDown()
// TODO: Port to quaternion-based camera
// TODO: Port to quaternion-based camera (?)
void UpdateCamera(Camera *camera)
{
static int swingCounter = 0; // Used for 1st person swinging movement
static Vector2 previousMousePosition = { 0.0f, 0.0f };
// TODO: Compute cameraTargetDistance and cameraAngle here
// TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
// Mouse movement detection
Vector2 mousePositionDelta = { 0.0f, 0.0f };
@ -275,20 +287,19 @@ void UpdateCamera(Camera *camera)
int mouseWheelMove = GetMouseWheelMove();
// Keys input detection
bool panKey = IsMouseButtonDown(cameraPanControlKey);
bool altKey = IsKeyDown(cameraAltControlKey);
bool szoomKey = IsKeyDown(cameraSmoothZoomControlKey);
bool panKey = IsMouseButtonDown(CAMERA.panControl);
bool altKey = IsKeyDown(CAMERA.altControl);
bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]),
IsKeyDown(CAMERA.moveControl[MOVE_BACK]),
IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]),
IsKeyDown(CAMERA.moveControl[MOVE_LEFT]),
IsKeyDown(CAMERA.moveControl[MOVE_UP]),
IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
bool direction[6] = { IsKeyDown(cameraMoveControl[MOVE_FRONT]),
IsKeyDown(cameraMoveControl[MOVE_BACK]),
IsKeyDown(cameraMoveControl[MOVE_RIGHT]),
IsKeyDown(cameraMoveControl[MOVE_LEFT]),
IsKeyDown(cameraMoveControl[MOVE_UP]),
IsKeyDown(cameraMoveControl[MOVE_DOWN]) };
// TODO: Touch input detection (probably gestures system required)
// TODO: Consider touch inputs for camera
if (cameraMode != CAMERA_CUSTOM)
if (CAMERA.mode != CAMERA_CUSTOM)
{
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
mousePositionDelta.y = mousePosition.y - previousMousePosition.y;
@ -297,58 +308,59 @@ void UpdateCamera(Camera *camera)
}
// Support for multiple automatic camera modes
switch (cameraMode)
// NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
switch (CAMERA.mode)
{
case CAMERA_FREE:
case CAMERA_FREE: // Camera free controls, using standard 3d-content-creation scheme
{
// Camera zoom
if ((cameraTargetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
{
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (cameraTargetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
}
// Camera looking down
// TODO: Review, weird comparisson of cameraTargetDistance == 120.0f?
else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
// TODO: Review, weird comparison of CAMERA.targetDistance == 120.0f?
else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
{
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
}
else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
{
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
// if (camera->target.y < 0) camera->target.y = -0.001;
}
else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
{
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
}
// Camera looking up
// TODO: Review, weird comparisson of cameraTargetDistance == 120.0f?
else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
// TODO: Review, weird comparisson of CAMERA.targetDistance == 120.0f?
else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
{
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
}
else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
{
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
// if (camera->target.y > 0) camera->target.y = 0.001;
}
else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
{
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
}
// Input keys checks
@ -359,150 +371,152 @@ void UpdateCamera(Camera *camera)
if (szoomKey)
{
// Camera smooth zoom
cameraTargetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
}
else
{
// Camera rotation
cameraAngle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
cameraAngle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
// Angle clamp
if (cameraAngle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
else if (cameraAngle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
}
}
else
{
// Camera panning
camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(cameraAngle.x)*sinf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.x)*sinf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
}
}
// Update camera position with changes
camera->position.x = -sinf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x;
camera->position.y = -sinf(cameraAngle.y)*cameraTargetDistance + camera->target.y;
camera->position.z = -cosf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.z;
camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y;
camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
} break;
case CAMERA_ORBITAL:
case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed
{
cameraAngle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom
CAMERA.angle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom
// Camera distance clamp
if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
// Update camera position with changes
camera->position.x = sinf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x;
camera->position.y = ((cameraAngle.y <= 0.0f)? 1 : -1)*sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
camera->position.z = cosf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.z;
camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
} break;
case CAMERA_FIRST_PERSON:
case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable
{
camera->position.x += (sinf(cameraAngle.x)*direction[MOVE_BACK] -
sinf(cameraAngle.x)*direction[MOVE_FRONT] -
cosf(cameraAngle.x)*direction[MOVE_LEFT] +
cosf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.y += (sinf(cameraAngle.y)*direction[MOVE_FRONT] -
sinf(cameraAngle.y)*direction[MOVE_BACK] +
camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.z += (cosf(cameraAngle.x)*direction[MOVE_BACK] -
cosf(cameraAngle.x)*direction[MOVE_FRONT] +
sinf(cameraAngle.x)*direction[MOVE_LEFT] -
sinf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
bool isMoving = false; // Required for swinging
for (int i = 0; i < 6; i++) if (direction[i]) { isMoving = true; break; }
camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
// Camera orientation calculation
cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
// Angle clamp
if (cameraAngle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
else if (cameraAngle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
// Camera is always looking at player
camera->target.x = camera->position.x - sinf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
camera->target.y = camera->position.y + sinf(cameraAngle.y)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
camera->target.z = camera->position.z - cosf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
// Recalculate camera target considering translation and rotation
Matrix translation = MatrixTranslate(0, 0, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER));
Matrix rotation = MatrixRotateXYZ((Vector3){ PI*2 - CAMERA.angle.y, PI*2 - CAMERA.angle.x, 0 });
Matrix transform = MatrixMultiply(translation, rotation);
if (isMoving) swingCounter++;
camera->target.x = camera->position.x - transform.m12;
camera->target.y = camera->position.y - transform.m13;
camera->target.z = camera->position.z - transform.m14;
// If movement detected (some key pressed), increase swinging
for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; }
// Camera position update
// NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
camera->position.y = playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
} break;
case CAMERA_THIRD_PERSON:
case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable
{
camera->position.x += (sinf(cameraAngle.x)*direction[MOVE_BACK] -
sinf(cameraAngle.x)*direction[MOVE_FRONT] -
cosf(cameraAngle.x)*direction[MOVE_LEFT] +
cosf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.y += (sinf(cameraAngle.y)*direction[MOVE_FRONT] -
sinf(cameraAngle.y)*direction[MOVE_BACK] +
camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.z += (cosf(cameraAngle.x)*direction[MOVE_BACK] -
cosf(cameraAngle.x)*direction[MOVE_FRONT] +
sinf(cameraAngle.x)*direction[MOVE_LEFT] -
sinf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
// Camera orientation calculation
cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
// Angle clamp
if (cameraAngle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
else if (cameraAngle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
// Camera zoom
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
// Camera distance clamp
if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
// TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target...
camera->position.x = sinf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x;
if (cameraAngle.y <= 0.0f) camera->position.y = sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
else camera->position.y = -sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
camera->position.z = cosf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.z;
camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
} break;
case CAMERA_CUSTOM: break;
default: break;
}
}
// Set camera pan key to combine with mouse movement (free camera)
void SetCameraPanControl(int panKey) { cameraPanControlKey = panKey; }
void SetCameraPanControl(int panKey) { CAMERA.panControl = panKey; }
// Set camera alt key to combine with mouse movement (free camera)
void SetCameraAltControl(int altKey) { cameraAltControlKey = altKey; }
void SetCameraAltControl(int altKey) { CAMERA.altControl = altKey; }
// Set camera smooth zoom key to combine with mouse (free camera)
void SetCameraSmoothZoomControl(int szoomKey) { cameraSmoothZoomControlKey = szoomKey; }
void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; }
// Set camera move controls (1st person and 3rd person cameras)
void SetCameraMoveControls(int frontKey, int backKey, int rightKey, int leftKey, int upKey, int downKey)
{
cameraMoveControl[MOVE_FRONT] = frontKey;
cameraMoveControl[MOVE_BACK] = backKey;
cameraMoveControl[MOVE_RIGHT] = rightKey;
cameraMoveControl[MOVE_LEFT] = leftKey;
cameraMoveControl[MOVE_UP] = upKey;
cameraMoveControl[MOVE_DOWN] = downKey;
CAMERA.moveControl[MOVE_FRONT] = frontKey;
CAMERA.moveControl[MOVE_BACK] = backKey;
CAMERA.moveControl[MOVE_RIGHT] = rightKey;
CAMERA.moveControl[MOVE_LEFT] = leftKey;
CAMERA.moveControl[MOVE_UP] = upKey;
CAMERA.moveControl[MOVE_DOWN] = downKey;
}
#endif // CAMERA_IMPLEMENTATION

View file

@ -18,6 +18,7 @@ package rl
#include "external/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c"
#include "external/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c"
#include "external/glfw/src/wayland-xdg-shell-client-protocol.c"
#include "external/glfw/src/wayland-xdg-decoration-client-protocol.c"
#include "external/glfw/src/wayland-viewporter-client-protocol.c"
#endif
#ifdef _GLFW_X11

View file

@ -6,7 +6,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2018-2019 Ahmad Fatoum & Ramon Santamaria (@raysan5)
* Copyright (c) 2018-2020 Ahmad Fatoum & Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -25,7 +25,7 @@
*
**********************************************************************************************/
#define RAYLIB_VERSION "2.6-dev"
#define RAYLIB_VERSION "3.0"
// Edit to control what features Makefile'd raylib is compiled with
#if defined(RAYLIB_CMAKE)
@ -48,16 +48,20 @@
#define SUPPORT_MOUSE_CURSOR_RPI 1
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
//#define SUPPORT_BUSY_WAIT_LOOP 1
// Use a half-busy wait loop, in this case frame sleeps for some time and runs a busy-wait-loop at the end
#define SUPPORT_HALFBUSY_WAIT_LOOP
// Wait for events passively (sleeping while no events) instead of polling them actively every frame
//#define SUPPORT_EVENTS_WAITING 1
// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
#define SUPPORT_SCREEN_CAPTURE 1
// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
#define SUPPORT_GIF_RECORDING 1
//#define SUPPORT_GIF_RECORDING 1
// Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP)
//#define SUPPORT_HIGH_DPI 1
// Support CompressData() and DecompressData() functions
#define SUPPORT_COMPRESSION_API 1
#define SUPPORT_COMPRESSION_API 1
// Support saving binary data automatically to a generated storage.data file. This file is managed internally.
#define SUPPORT_DATA_STORAGE 1
//------------------------------------------------------------------------------------
// Module: rlgl - Configuration Flags
@ -65,7 +69,6 @@
// Support VR simulation functionality (stereo rendering)
#define SUPPORT_VR_SIMULATOR 1
//------------------------------------------------------------------------------------
// Module: shapes - Configuration Flags
//------------------------------------------------------------------------------------
@ -81,15 +84,15 @@
//------------------------------------------------------------------------------------
// Selecte desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1
//#define SUPPORT_FILEFORMAT_JPG 1
//#define SUPPORT_FILEFORMAT_GIF 1
#define SUPPORT_FILEFORMAT_BMP 1
#define SUPPORT_FILEFORMAT_TGA 1
#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1
//#define SUPPORT_FILEFORMAT_PSD 1
//#define SUPPORT_FILEFORMAT_DDS 1
#define SUPPORT_FILEFORMAT_DDS 1
#define SUPPORT_FILEFORMAT_HDR 1
//#define SUPPORT_FILEFORMAT_KTX 1
//#define SUPPORT_FILEFORMAT_ASTC 1
#define SUPPORT_FILEFORMAT_KTX 1
#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1
@ -101,7 +104,6 @@
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
#define SUPPORT_IMAGE_GENERATION 1
//------------------------------------------------------------------------------------
// Module: text - Configuration Flags
//------------------------------------------------------------------------------------
@ -112,7 +114,6 @@
#define SUPPORT_FILEFORMAT_FNT 1
#define SUPPORT_FILEFORMAT_TTF 1
//------------------------------------------------------------------------------------
// Module: models - Configuration Flags
//------------------------------------------------------------------------------------
@ -125,7 +126,6 @@
// NOTE: Some generated meshes DO NOT include generated texture coordinates
#define SUPPORT_MESH_GENERATION 1
//------------------------------------------------------------------------------------
// Module: audio - Configuration Flags
//------------------------------------------------------------------------------------
@ -134,16 +134,15 @@
#define SUPPORT_FILEFORMAT_OGG 1
#define SUPPORT_FILEFORMAT_XM 1
#define SUPPORT_FILEFORMAT_MOD 1
#define SUPPORT_FILEFORMAT_FLAC 1
//#define SUPPORT_FILEFORMAT_FLAC 1
#define SUPPORT_FILEFORMAT_MP3 1
//------------------------------------------------------------------------------------
// Module: utils - Configuration Flags
//------------------------------------------------------------------------------------
// Show TraceLog() output messages
// Show TRACELOG() output messages
// NOTE: By default LOG_DEBUG traces not shown
#define SUPPORT_TRACELOG 1
#define SUPPORT_TRACELOG 1
//#define SUPPORT_TRACELOG_DEBUG 1
#endif //defined(RAYLIB_CMAKE)

File diff suppressed because it is too large Load diff

View file

@ -463,17 +463,17 @@ func TakeScreenshot(name string) {
C.TakeScreenshot(cname)
}
// StorageSaveValue - Storage save integer value (to defined position)
func StorageSaveValue(position, value int32) {
cposition := (C.int)(position)
// SaveStorageValue - Storage save integer value (to defined position)
func SaveStorageValue(position, value int32) {
cposition := (C.uint)(position)
cvalue := (C.int)(value)
C.StorageSaveValue(cposition, cvalue)
C.SaveStorageValue(cposition, cvalue)
}
// StorageLoadValue - Storage load integer value (from defined position)
func StorageLoadValue(position int32) int32 {
cposition := (C.int)(position)
ret := C.StorageLoadValue(cposition)
// LoadStorageValue - Storage load integer value (from defined position)
func LoadStorageValue(position int32) int32 {
cposition := (C.uint)(position)
ret := C.LoadStorageValue(cposition)
v := (int32)(ret)
return v
}

File diff suppressed because it is too large Load diff

View file

@ -1,34 +1,10 @@
#ifndef DIRENT_H
#define DIRENT_H
/*
/****************************************************************************
Declaration of POSIX directory browsing functions and types for Win32.
Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
History: Created March 1997. Updated June 2003.
Rights: See end of file.
*/
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct DIR DIR;
struct dirent
{
char *d_name;
};
DIR *opendir(const char *);
int closedir(DIR *);
struct dirent *readdir(DIR *);
void rewinddir(DIR *);
/*
Reviewed by Ramon Santamaria for raylib on January 2020.
Copyright Kevlin Henney, 1997, 2003. All rights reserved.
@ -41,7 +17,41 @@ void rewinddir(DIR *);
But that said, if there are any problems please get in touch.
*/
****************************************************************************/
#ifndef DIRENT_H
#define DIRENT_H
// Allow custom memory allocators
#ifndef DIRENT_MALLOC
#define DIRENT_MALLOC(sz) malloc(sz)
#endif
#ifndef DIRENT_FREE
#define DIRENT_FREE(p) free(p)
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Fordward declaration of DIR, implementation below
typedef struct DIR DIR;
struct dirent {
char *d_name;
};
#ifdef __cplusplus
extern "C" {
#endif
//------------------------------------------------------------------------------------
// Functions Declaration
//------------------------------------------------------------------------------------
DIR *opendir(const char *name);
int closedir(DIR *dir);
struct dirent *readdir(DIR *dir);
void rewinddir(DIR *dir);
#ifdef __cplusplus
}
@ -49,142 +59,15 @@ void rewinddir(DIR *);
#endif // DIRENT_H
/*
/****************************************************************************
Implementation of POSIX directory browsing functions and types for Win32.
Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
History: Created March 1997. Updated June 2003 and July 2012.
Rights: See end of file.
History: Created March 1997. Updated June 2003.
Reviewed by Ramon Santamaria for raylib on January 2020.
*/
#include <errno.h>
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
struct DIR
{
handle_type handle; /* -1 for failed rewind */
struct _finddata_t info;
struct dirent result; /* d_name null iff first time */
char *name; /* null-terminated char string */
};
DIR *opendir(const char *name)
{
DIR *dir = 0;
if(name && name[0])
{
size_t base_length = strlen(name);
const char *all = /* search pattern must end with suitable wildcard */
strchr("/\\", name[base_length - 1]) ? "*" : "/*";
if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
(dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
{
strcat(strcpy(dir->name, name), all);
if((dir->handle =
(handle_type) _findfirst(dir->name, &dir->info)) != -1)
{
dir->result.d_name = 0;
}
else /* rollback */
{
free(dir->name);
free(dir);
dir = 0;
}
}
else /* rollback */
{
free(dir);
dir = 0;
errno = ENOMEM;
}
}
else
{
errno = EINVAL;
}
return dir;
}
int closedir(DIR *dir)
{
int result = -1;
if(dir)
{
if(dir->handle != -1)
{
result = _findclose(dir->handle);
}
free(dir->name);
free(dir);
}
if(result == -1) /* map all errors to EBADF */
{
errno = EBADF;
}
return result;
}
struct dirent *readdir(DIR *dir)
{
struct dirent *result = 0;
if(dir && dir->handle != -1)
{
if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
{
result = &dir->result;
result->d_name = dir->info.name;
}
}
else
{
errno = EBADF;
}
return result;
}
void rewinddir(DIR *dir)
{
if(dir && dir->handle != -1)
{
_findclose(dir->handle);
dir->handle = (handle_type) _findfirst(dir->name, &dir->info);
dir->result.d_name = 0;
}
else
{
errno = EBADF;
}
}
#ifdef __cplusplus
}
#endif
/*
Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
Copyright Kevlin Henney, 1997, 2003. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose is hereby granted without fee, provided
@ -195,4 +78,106 @@ void rewinddir(DIR *dir)
But that said, if there are any problems please get in touch.
*/
****************************************************************************/
#include <io.h> // _findfirst and _findnext set errno iff they return -1
#include <stdlib.h>
#include <string.h>
#include <errno.h>
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef ptrdiff_t handle_type; // C99's intptr_t not sufficiently portable
struct DIR {
handle_type handle; // -1 for failed rewind
struct _finddata_t info;
struct dirent result; // d_name null iff first time
char *name; // null-terminated char string
};
DIR *opendir(const char *name)
{
DIR *dir = 0;
if (name && name[0])
{
size_t base_length = strlen(name);
// Search pattern must end with suitable wildcard
const char *all = strchr("/\\", name[base_length - 1]) ? "*" : "/*";
if ((dir = (DIR *)DIRENT_MALLOC(sizeof *dir)) != 0 &&
(dir->name = (char *)DIRENT_MALLOC(base_length + strlen(all) + 1)) != 0)
{
strcat(strcpy(dir->name, name), all);
if ((dir->handle = (handle_type) _findfirst(dir->name, &dir->info)) != -1)
{
dir->result.d_name = 0;
}
else // rollback
{
DIRENT_FREE(dir->name);
DIRENT_FREE(dir);
dir = 0;
}
}
else // rollback
{
DIRENT_FREE(dir);
dir = 0;
errno = ENOMEM;
}
}
else errno = EINVAL;
return dir;
}
int closedir(DIR *dir)
{
int result = -1;
if (dir)
{
if (dir->handle != -1) result = _findclose(dir->handle);
DIRENT_FREE(dir->name);
DIRENT_FREE(dir);
}
// NOTE: All errors ampped to EBADF
if (result == -1) errno = EBADF;
return result;
}
struct dirent *readdir(DIR *dir)
{
struct dirent *result = 0;
if (dir && dir->handle != -1)
{
if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
{
result = &dir->result;
result->d_name = dir->info.name;
}
}
else errno = EBADF;
return result;
}
void rewinddir(DIR *dir)
{
if (dir && dir->handle != -1)
{
_findclose(dir->handle);
dir->handle = (handle_type) _findfirst(dir->name, &dir->info);
dir->result.d_name = 0;
}
else errno = EBADF;
}

View file

@ -40,6 +40,14 @@
#define APIENTRYP APIENTRY *
#endif
// RAY: Added
#ifndef GLAD_REALLOC
#define GLAD_REALLOC(n,sz) realloc(n,sz)
#endif
#ifndef GLAD_FREE
#define GLAD_FREE(p) free(p)
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -3760,7 +3768,7 @@ static int get_exts(void) {
num_exts_i = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i);
if (num_exts_i > 0) {
exts_i = (const char **)realloc((void *)exts_i, num_exts_i * sizeof *exts_i);
exts_i = (const char **)GLAD_REALLOC((void *)exts_i, num_exts_i * sizeof *exts_i);
}
if (exts_i == NULL) {
@ -3777,7 +3785,7 @@ static int get_exts(void) {
static void free_exts(void) {
if (exts_i != NULL) {
free((char **)exts_i);
GLAD_FREE((char **)exts_i);
exts_i = NULL;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*************************************************************************
* GLFW 3.3 - www.glfw.org
* GLFW 3.4 - www.glfw.org
* A library for OpenGL, window and input
*------------------------------------------------------------------------
* Copyright (c) 2002-2006 Marcus Geelnard
@ -89,7 +89,7 @@ extern "C" {
#undef APIENTRY
#undef GLFW_APIENTRY_DEFINED
#endif
// RAY: Actually, only HWND handler needs to be defined
// @raysan5: Actually, only HWND handler needs to be defined
// Including windows.h could suppose symbols re-definition issues (i.e Rectangle type)
//#include <windows.h>
typedef void *PVOID;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@ -23,6 +23,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
#include <sys/param.h> // For MAXPATHLEN
@ -429,9 +431,8 @@ static GLFWbool initializeTIS(void)
// In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
// Menu bar setup must go between sharedApplication above and
// finishLaunching below, in order to properly emulate the behavior
// of NSApplicationMain
// Menu bar setup must go between sharedApplication and finishLaunching
// in order to properly emulate the behavior of NSApplicationMain
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
{
@ -446,9 +447,9 @@ static GLFWbool initializeTIS(void)
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
[NSApp stop:nil];
_glfw.ns.finishedLaunching = GLFW_TRUE;
_glfwPlatformPostEmptyEvent();
[NSApp stop:nil];
}
- (void)applicationDidHide:(NSNotification *)notification
@ -462,6 +463,32 @@ static GLFWbool initializeTIS(void)
@end // GLFWApplicationDelegate
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void* _glfwLoadLocalVulkanLoaderNS(void)
{
CFBundleRef bundle = CFBundleGetMainBundle();
if (!bundle)
return NULL;
CFURLRef url =
CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
if (!url)
return NULL;
char path[PATH_MAX];
void* handle = NULL;
if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
handle = _glfw_dlopen(path);
CFRelease(url);
return handle;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Cocoa - www.glfw.org
// GLFW 3.4 Cocoa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//
@ -30,7 +30,7 @@
#include <IOKit/hid/IOHIDKeys.h>
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyJoystick; }
#define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Cocoa - www.glfw.org
// GLFW 3.4 Cocoa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -329,7 +331,7 @@ void _glfwInitJoysticksNS(void)
return;
}
for (int i = 0; i < sizeof(usages) / sizeof(long); i++)
for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++)
{
const long page = kHIDPage_GenericDesktop;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -142,7 +144,7 @@ static GLFWbool modeIsGood(CGDisplayModeRef mode)
// Convert Core Graphics display mode to GLFW video mode
//
static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
CVDisplayLinkRef link)
double fallbackRefreshRate)
{
GLFWvidmode result;
result.width = (int) CGDisplayModeGetWidth(mode);
@ -150,11 +152,7 @@ static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
result.refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode));
if (result.refreshRate == 0)
{
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
if (!(time.flags & kCVTimeIsIndefinite))
result.refreshRate = (int) (time.timeScale / (double) time.timeValue);
}
result.refreshRate = (int) round(fallbackRefreshRate);
#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
@ -213,7 +211,7 @@ static void endFadeReservation(CGDisplayFadeReservationToken token)
// Finds and caches the NSScreen corresponding to the specified monitor
//
GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor)
static GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor)
{
if (monitor->ns.screen)
return GLFW_TRUE;
@ -236,6 +234,68 @@ GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor)
return GLFW_FALSE;
}
// Returns the display refresh rate queried from the I/O registry
//
static double getFallbackRefreshRate(CGDirectDisplayID displayID)
{
double refreshRate = 60.0;
io_iterator_t it;
io_service_t service;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching("IOFramebuffer"),
&it) != 0)
{
return refreshRate;
}
while ((service = IOIteratorNext(it)) != 0)
{
const CFNumberRef indexRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFramebufferOpenGLIndex"),
kCFAllocatorDefault,
kNilOptions);
if (!indexRef)
continue;
uint32_t index = 0;
CFNumberGetValue(indexRef, kCFNumberIntType, &index);
CFRelease(indexRef);
if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID)
continue;
const CFNumberRef clockRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFBCurrentPixelClock"),
kCFAllocatorDefault,
kNilOptions);
const CFNumberRef countRef =
IORegistryEntryCreateCFProperty(service,
CFSTR("IOFBCurrentPixelCount"),
kCFAllocatorDefault,
kNilOptions);
if (!clockRef || !countRef)
break;
uint32_t clock = 0, count = 0;
CFNumberGetValue(clockRef, kCFNumberIntType, &clock);
CFNumberGetValue(countRef, kCFNumberIntType, &count);
CFRelease(clockRef);
CFRelease(countRef);
if (clock > 0 && count > 0)
refreshRate = clock / (double) count;
break;
}
IOObjectRelease(it);
return refreshRate;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
@ -245,18 +305,16 @@ GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor)
//
void _glfwPollMonitorsNS(void)
{
uint32_t i, j, displayCount, disconnectedCount;
CGDirectDisplayID* displays;
_GLFWmonitor** disconnected = NULL;
uint32_t displayCount;
CGGetOnlineDisplayList(0, NULL, &displayCount);
displays = calloc(displayCount, sizeof(CGDirectDisplayID));
CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID));
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
for (i = 0; i < _glfw.monitorCount; i++)
for (int i = 0; i < _glfw.monitorCount; i++)
_glfw.monitors[i]->ns.screen = nil;
disconnectedCount = _glfw.monitorCount;
_GLFWmonitor** disconnected = NULL;
uint32_t disconnectedCount = _glfw.monitorCount;
if (disconnectedCount)
{
disconnected = calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
@ -265,19 +323,17 @@ void _glfwPollMonitorsNS(void)
_glfw.monitorCount * sizeof(_GLFWmonitor*));
}
for (i = 0; i < displayCount; i++)
for (uint32_t i = 0; i < displayCount; i++)
{
_GLFWmonitor* monitor;
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
if (CGDisplayIsAsleep(displays[i]))
continue;
for (j = 0; j < disconnectedCount; j++)
// HACK: Compare unit numbers instead of display IDs to work around
// display replacement on machines with automatic graphics
// switching
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
for (uint32_t j = 0; j < disconnectedCount; j++)
{
// HACK: Compare unit numbers instead of display IDs to work around
// display replacement on machines with automatic graphics
// switching
if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
{
disconnected[j] = NULL;
@ -290,16 +346,21 @@ void _glfwPollMonitorsNS(void)
if (!name)
name = _glfw_strdup("Unknown");
monitor = _glfwAllocMonitor(name, size.width, size.height);
_GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height);
monitor->ns.displayID = displays[i];
monitor->ns.unitNumber = unitNumber;
free(name);
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
if (CGDisplayModeGetRefreshRate(mode) == 0.0)
monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]);
CGDisplayModeRelease(mode);
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
}
for (i = 0; i < disconnectedCount; i++)
for (uint32_t i = 0; i < disconnectedCount; i++)
{
if (disconnected[i])
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
@ -313,30 +374,25 @@ void _glfwPollMonitorsNS(void)
//
void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
CFArrayRef modes;
CFIndex count, i;
CVDisplayLinkRef link;
CGDisplayModeRef native = NULL;
GLFWvidmode current;
const GLFWvidmode* best;
best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current);
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
if (_glfwCompareVideoModes(&current, best) == 0)
return;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
const CFIndex count = CFArrayGetCount(modes);
CGDisplayModeRef native = NULL;
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
count = CFArrayGetCount(modes);
for (i = 0; i < count; i++)
for (CFIndex i = 0; i < count; i++)
{
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
if (!modeIsGood(dm))
continue;
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
const GLFWvidmode mode =
vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
if (_glfwCompareVideoModes(best, &mode) == 0)
{
native = dm;
@ -355,7 +411,6 @@ void _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
}
CFRelease(modes);
CVDisplayLinkRelease(link);
}
// Restore the previously saved (original) video mode
@ -443,26 +498,21 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
{
@autoreleasepool {
CFArrayRef modes;
CFIndex found, i, j;
GLFWvidmode* result;
CVDisplayLinkRef link;
*count = 0;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
const CFIndex found = CFArrayGetCount(modes);
GLFWvidmode* result = calloc(found, sizeof(GLFWvidmode));
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
found = CFArrayGetCount(modes);
result = calloc(found, sizeof(GLFWvidmode));
for (i = 0; i < found; i++)
for (CFIndex i = 0; i < found; i++)
{
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
if (!modeIsGood(dm))
continue;
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
const GLFWvidmode mode =
vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
CFIndex j;
for (j = 0; j < *count; j++)
{
@ -479,7 +529,6 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
}
CFRelease(modes);
CVDisplayLinkRelease(link);
return result;
} // autoreleasepool
@ -489,16 +538,9 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
{
@autoreleasepool {
CGDisplayModeRef displayMode;
CVDisplayLinkRef link;
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
*mode = vidmodeFromCGDisplayMode(displayMode, link);
CGDisplayModeRelease(displayMode);
CVDisplayLinkRelease(link);
CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
*mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate);
CGDisplayModeRelease(native);
} // autoreleasepool
}
@ -507,7 +549,7 @@ GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
@autoreleasepool {
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
uint32_t size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
CGGetDisplayTransferByTable(monitor->ns.displayID,
@ -519,7 +561,7 @@ GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
_glfwAllocGammaArrays(ramp, size);
for (i = 0; i < size; i++)
for (uint32_t i = 0; i < size; i++)
{
ramp->red[i] = (unsigned short) (values[i] * 65535);
ramp->green[i] = (unsigned short) (values[i + size] * 65535);
@ -536,10 +578,9 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
@autoreleasepool {
int i;
CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue));
for (i = 0; i < ramp->size; i++)
for (unsigned int i = 0; i < ramp->size; i++)
{
values[i] = ramp->red[i] / 65535.f;
values[i + ramp->size] = ramp->green[i] / 65535.f;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@ -28,8 +28,6 @@
#include <dlfcn.h>
#include <Carbon/Carbon.h>
#include <CoreVideo/CVBase.h>
#include <CoreVideo/CVDisplayLink.h>
// NOTE: All of NSGL was deprecated in the 10.14 SDK
// This disables the pointless warnings for every symbol we use
@ -41,6 +39,9 @@
typedef void* id;
#endif
// NOTE: Many Cocoa enum values have been renamed and we need to build across
// SDK versions where one is unavailable or the other deprecated
// We use the newer names in code and these macros to handle compatibility
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
#define NSEventMaskAny NSAnyEventMask
@ -60,6 +61,7 @@ typedef void* id;
#endif
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef VkFlags VkMetalSurfaceCreateFlagsEXT;
typedef struct VkMacOSSurfaceCreateInfoMVK
{
@ -69,7 +71,16 @@ typedef struct VkMacOSSurfaceCreateInfoMVK
const void* pView;
} VkMacOSSurfaceCreateInfoMVK;
typedef struct VkMetalSurfaceCreateInfoEXT
{
VkStructureType sType;
const void* pNext;
VkMetalSurfaceCreateFlagsEXT flags;
const void* pLayer;
} VkMetalSurfaceCreateInfoEXT;
typedef VkResult (APIENTRY *PFN_vkCreateMacOSSurfaceMVK)(VkInstance,const VkMacOSSurfaceCreateInfoMVK*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMetalSurfaceCreateInfoEXT*,const VkAllocationCallbacks*,VkSurfaceKHR*);
#include "posix_thread.h"
#include "cocoa_joystick.h"
@ -139,7 +150,7 @@ typedef struct _GLFWlibraryNS
id keyUpMonitor;
id nibObjects;
char keyName[64];
char keynames[GLFW_KEY_LAST + 1][17];
short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1];
char* clipboardString;
@ -167,6 +178,7 @@ typedef struct _GLFWmonitorNS
CGDisplayModeRef previousMode;
uint32_t unitNumber;
id screen;
double fallbackRefreshRate;
} _GLFWmonitorNS;
@ -195,3 +207,5 @@ void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
float _glfwTransformYNS(float y);
void* _glfwLoadLocalVulkanLoaderNS(void);

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//
@ -23,6 +23,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@ -23,6 +23,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -33,15 +35,14 @@
//
static NSUInteger getStyleMask(_GLFWwindow* window)
{
NSUInteger styleMask = 0;
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
if (window->monitor || !window->decorated)
styleMask |= NSWindowStyleMaskBorderless;
else
{
styleMask |= NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable;
NSWindowStyleMaskClosable;
if (window->resizable)
styleMask |= NSWindowStyleMaskResizable;
@ -321,12 +322,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
_glfwInputWindowFocus(window, GLFW_FALSE);
}
- (void)windowDidChangeScreen:(NSNotification *)notification
{
if (window->context.source == GLFW_NATIVE_CONTEXT_API)
_glfwUpdateDisplayLinkDisplayNSGL(window);
}
@end
@ -610,10 +605,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)scrollWheel:(NSEvent *)event
{
double deltaX, deltaY;
deltaX = [event scrollingDeltaX];
deltaY = [event scrollingDeltaY];
double deltaX = [event scrollingDeltaX];
double deltaY = [event scrollingDeltaY];
if ([event hasPreciseScrollingDeltas])
{
@ -730,9 +723,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
else
characters = (NSString*) string;
NSUInteger i, length = [characters length];
for (i = 0; i < length; i++)
const NSUInteger length = [characters length];
for (NSUInteger i = 0; i < length; i++)
{
const unichar codepoint = [characters characterAtIndex:i];
if ((codepoint & 0xff00) == 0xf700)
@ -817,7 +809,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
else
{
[window->ns.object center];
[(NSWindow*) window->ns.object center];
_glfw.ns.cascadePoint =
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
@ -893,10 +885,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
@autoreleasepool {
if (!_glfw.ns.finishedLaunching)
{
[NSApp run];
_glfw.ns.finishedLaunching = GLFW_TRUE;
}
if (!createNativeWindow(window, wndconfig, fbconfig))
return GLFW_FALSE;
@ -963,16 +952,20 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
[window->ns.object close];
window->ns.object = nil;
// HACK: Allow Cocoa to catch up before returning
_glfwPlatformPollEvents();
} // autoreleasepool
}
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title)
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
{
@autoreleasepool {
[window->ns.object setTitle:@(title)];
NSString* string = @(title);
[window->ns.object setTitle:string];
// HACK: Set the miniwindow title explicitly as setTitle: doesn't update it
// if the window lacks NSWindowStyleMaskTitled
[window->ns.object setMiniwindowTitle:@(title)];
[window->ns.object setMiniwindowTitle:string];
} // autoreleasepool
}
@ -1033,7 +1026,14 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
acquireMonitor(window);
}
else
[window->ns.object setContentSize:NSMakeSize(width, height)];
{
NSRect contentRect =
[window->ns.object contentRectForFrameRect:[window->ns.object frame]];
contentRect.origin.y += contentRect.size.height - height;
contentRect.size = NSMakeSize(width, height);
[window->ns.object setFrame:[window->ns.object frameRectForContentRect:contentRect]
display:YES];
}
} // autoreleasepool
}
@ -1222,7 +1222,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
// HACK: Changing the style mask can cause the first responder to be cleared
[window->ns.object makeFirstResponder:window->ns.view];
if (monitor)
if (window->monitor)
{
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
[window->ns.object setHasShadow:NO];
@ -1377,6 +1377,9 @@ void _glfwPlatformPollEvents(void)
{
@autoreleasepool {
if (!_glfw.ns.finishedLaunching)
[NSApp run];
for (;;)
{
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
@ -1396,6 +1399,9 @@ void _glfwPlatformWaitEvents(void)
{
@autoreleasepool {
if (!_glfw.ns.finishedLaunching)
[NSApp run];
// I wanted to pass NO to dequeue:, and rely on PollEvents to
// dequeue and send. For reasons not at all clear to me, passing
// NO to dequeue: causes this method never to return.
@ -1414,6 +1420,9 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
{
@autoreleasepool {
if (!_glfw.ns.finishedLaunching)
[NSApp run];
NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout];
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:date
@ -1431,6 +1440,9 @@ void _glfwPlatformPostEmptyEvent(void)
{
@autoreleasepool {
if (!_glfw.ns.finishedLaunching)
[NSApp run];
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSMakePoint(0, 0)
modifierFlags:0
@ -1504,8 +1516,17 @@ const char* _glfwPlatformGetScancodeName(int scancode)
{
@autoreleasepool {
if (scancode < 0 || scancode > 0xff ||
_glfw.ns.keycodes[scancode] == GLFW_KEY_UNKNOWN)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");
return NULL;
}
const int key = _glfw.ns.keycodes[scancode];
UInt32 deadKeyState = 0;
UniChar characters[8];
UniChar characters[4];
UniCharCount characterCount = 0;
if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes],
@ -1530,12 +1551,12 @@ const char* _glfwPlatformGetScancodeName(int scancode)
characterCount,
kCFAllocatorNull);
CFStringGetCString(string,
_glfw.ns.keyName,
sizeof(_glfw.ns.keyName),
_glfw.ns.keynames[key],
sizeof(_glfw.ns.keynames[key]),
kCFStringEncodingUTF8);
CFRelease(string);
return _glfw.ns.keyName;
return _glfw.ns.keynames[key];
} // autoreleasepool
}
@ -1593,23 +1614,49 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{
@autoreleasepool {
if (shape == GLFW_ARROW_CURSOR)
cursor->ns.object = [NSCursor arrowCursor];
else if (shape == GLFW_IBEAM_CURSOR)
cursor->ns.object = [NSCursor IBeamCursor];
else if (shape == GLFW_CROSSHAIR_CURSOR)
cursor->ns.object = [NSCursor crosshairCursor];
else if (shape == GLFW_HAND_CURSOR)
cursor->ns.object = [NSCursor pointingHandCursor];
else if (shape == GLFW_HRESIZE_CURSOR)
cursor->ns.object = [NSCursor resizeLeftRightCursor];
else if (shape == GLFW_VRESIZE_CURSOR)
cursor->ns.object = [NSCursor resizeUpDownCursor];
SEL cursorSelector = NULL;
// HACK: Try to use a private message
if (shape == GLFW_RESIZE_EW_CURSOR)
cursorSelector = NSSelectorFromString(@"_windowResizeEastWestCursor");
else if (shape == GLFW_RESIZE_NS_CURSOR)
cursorSelector = NSSelectorFromString(@"_windowResizeNorthSouthCursor");
else if (shape == GLFW_RESIZE_NWSE_CURSOR)
cursorSelector = NSSelectorFromString(@"_windowResizeNorthWestSouthEastCursor");
else if (shape == GLFW_RESIZE_NESW_CURSOR)
cursorSelector = NSSelectorFromString(@"_windowResizeNorthEastSouthWestCursor");
if (cursorSelector && [NSCursor respondsToSelector:cursorSelector])
{
id object = [NSCursor performSelector:cursorSelector];
if ([object isKindOfClass:[NSCursor class]])
cursor->ns.object = object;
}
if (!cursor->ns.object)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to retrieve standard cursor");
if (shape == GLFW_ARROW_CURSOR)
cursor->ns.object = [NSCursor arrowCursor];
else if (shape == GLFW_IBEAM_CURSOR)
cursor->ns.object = [NSCursor IBeamCursor];
else if (shape == GLFW_CROSSHAIR_CURSOR)
cursor->ns.object = [NSCursor crosshairCursor];
else if (shape == GLFW_POINTING_HAND_CURSOR)
cursor->ns.object = [NSCursor pointingHandCursor];
else if (shape == GLFW_RESIZE_EW_CURSOR)
cursor->ns.object = [NSCursor resizeLeftRightCursor];
else if (shape == GLFW_RESIZE_NS_CURSOR)
cursor->ns.object = [NSCursor resizeUpDownCursor];
else if (shape == GLFW_RESIZE_ALL_CURSOR)
cursor->ns.object = [NSCursor closedHandCursor];
else if (shape == GLFW_NOT_ALLOWED_CURSOR)
cursor->ns.object = [NSCursor operationNotAllowedCursor];
}
if (!cursor->ns.object)
{
_glfwInputError(GLFW_CURSOR_UNAVAILABLE,
"Cocoa: Standard cursor shape unavailable");
return GLFW_FALSE;
}
@ -1675,11 +1722,16 @@ const char* _glfwPlatformGetClipboardString(void)
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
{
if (!_glfw.vk.KHR_surface || !_glfw.vk.MVK_macos_surface)
return;
extensions[0] = "VK_KHR_surface";
extensions[1] = "VK_MVK_macos_surface";
if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface)
{
extensions[0] = "VK_KHR_surface";
extensions[1] = "VK_EXT_metal_surface";
}
else if (_glfw.vk.KHR_surface && _glfw.vk.MVK_macos_surface)
{
extensions[0] = "VK_KHR_surface";
extensions[1] = "VK_MVK_macos_surface";
}
}
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
@ -1697,19 +1749,6 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
@autoreleasepool {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
VkResult err;
VkMacOSSurfaceCreateInfoMVK sci;
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK;
vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)
vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK");
if (!vkCreateMacOSSurfaceMVK)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Cocoa: Vulkan instance missing VK_MVK_macos_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
// HACK: Dynamically load Core Animation to avoid adding an extra
// dependency for the majority who don't use MoltenVK
NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"];
@ -1735,11 +1774,49 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
[window->ns.view setLayer:window->ns.layer];
[window->ns.view setWantsLayer:YES];
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
sci.pView = window->ns.view;
VkResult err;
if (_glfw.vk.EXT_metal_surface)
{
VkMetalSurfaceCreateInfoEXT sci;
PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT;
vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT)
vkGetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT");
if (!vkCreateMetalSurfaceEXT)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Cocoa: Vulkan instance missing VK_EXT_metal_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
sci.pLayer = window->ns.layer;
err = vkCreateMetalSurfaceEXT(instance, &sci, allocator, surface);
}
else
{
VkMacOSSurfaceCreateInfoMVK sci;
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK;
vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)
vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK");
if (!vkCreateMacOSSurfaceMVK)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Cocoa: Vulkan instance missing VK_MVK_macos_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
sci.pView = window->ns.view;
err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface);
}
err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 EGL - www.glfw.org
// GLFW 3.4 EGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -121,23 +123,24 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
continue;
#if defined(_GLFW_X11)
XVisualInfo vi = {0};
// Only consider EGLConfigs with associated Visuals
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
if (!vi.visualid)
continue;
if (desired->transparent)
{
int count;
XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display,
VisualIDMask, &vi,
&count);
if (vis)
XVisualInfo vi = {0};
// Only consider EGLConfigs with associated Visuals
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
if (!vi.visualid)
continue;
if (desired->transparent)
{
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
XFree(vis);
int count;
XVisualInfo* vis =
XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
if (vis)
{
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
XFree(vis);
}
}
}
#endif // _GLFW_X11

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 EGL - www.glfw.org
// GLFW 3.4 EGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@ -47,26 +47,26 @@ typedef struct wl_egl_window* EGLNativeWindowType;
#error "No supported EGL platform selected"
#endif
#define EGL_SUCCESS 0x3000
#define EGL_NOT_INITIALIZED 0x3001
#define EGL_SUCCESS 0x3000
#define EGL_NOT_INITIALIZED 0x3001
#define EGL_BAD_ACCESS 0x3002
#define EGL_BAD_ALLOC 0x3003
#define EGL_BAD_ATTRIBUTE 0x3004
#define EGL_BAD_CONFIG 0x3005
#define EGL_BAD_CONTEXT 0x3006
#define EGL_BAD_CURRENT_SURFACE 0x3007
#define EGL_BAD_DISPLAY 0x3008
#define EGL_BAD_CONTEXT 0x3006
#define EGL_BAD_CURRENT_SURFACE 0x3007
#define EGL_BAD_DISPLAY 0x3008
#define EGL_BAD_MATCH 0x3009
#define EGL_BAD_NATIVE_PIXMAP 0x300a
#define EGL_BAD_NATIVE_WINDOW 0x300b
#define EGL_BAD_PARAMETER 0x300c
#define EGL_BAD_SURFACE 0x300d
#define EGL_BAD_SURFACE 0x300d
#define EGL_CONTEXT_LOST 0x300e
#define EGL_COLOR_BUFFER_TYPE 0x303f
#define EGL_RGB_BUFFER 0x308e
#define EGL_SURFACE_TYPE 0x3033
#define EGL_WINDOW_BIT 0x0004
#define EGL_RENDERABLE_TYPE 0x3040
#define EGL_RENDERABLE_TYPE 0x3040
#define EGL_OPENGL_ES_BIT 0x0001
#define EGL_OPENGL_ES2_BIT 0x0004
#define EGL_OPENGL_BIT 0x0008
@ -76,7 +76,7 @@ typedef struct wl_egl_window* EGLNativeWindowType;
#define EGL_RED_SIZE 0x3024
#define EGL_DEPTH_SIZE 0x3025
#define EGL_STENCIL_SIZE 0x3026
#define EGL_SAMPLES 0x3031
#define EGL_SAMPLES 0x3031
#define EGL_OPENGL_ES_API 0x30a0
#define EGL_OPENGL_API 0x30a2
#define EGL_NONE 0x3038

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 GLX - www.glfw.org
// GLFW 3.4 GLX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -226,8 +228,6 @@ static GLFWglproc getProcAddressGLX(const char* procname)
return _glfw_dlsym(_glfw.glx.handle, procname);
}
// Destroy the OpenGL context
//
static void destroyContextGLX(_GLFWwindow* window)
{
if (window->context.glx.window)

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 GLX - www.glfw.org
// GLFW 3.4 GLX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@ -29,11 +29,11 @@
#define GLX_RGBA_BIT 0x00000001
#define GLX_WINDOW_BIT 0x00000001
#define GLX_DRAWABLE_TYPE 0x8010
#define GLX_RENDER_TYPE 0x8011
#define GLX_RENDER_TYPE 0x8011
#define GLX_RGBA_TYPE 0x8014
#define GLX_DOUBLEBUFFER 5
#define GLX_STEREO 6
#define GLX_AUX_BUFFERS 7
#define GLX_AUX_BUFFERS 7
#define GLX_RED_SIZE 8
#define GLX_GREEN_SIZE 9
#define GLX_BLUE_SIZE 10
@ -42,7 +42,7 @@
#define GLX_STENCIL_SIZE 13
#define GLX_ACCUM_RED_SIZE 14
#define GLX_ACCUM_GREEN_SIZE 15
#define GLX_ACCUM_BLUE_SIZE 16
#define GLX_ACCUM_BLUE_SIZE 16
#define GLX_ACCUM_ALPHA_SIZE 17
#define GLX_SAMPLES 0x186a1
#define GLX_VISUAL_ID 0x800b

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
#include "mappings.h"
@ -187,6 +189,8 @@ void _glfwInputError(int code, const char* format, ...)
strcpy(description, "The requested format is unavailable");
else if (code == GLFW_NO_WINDOW_CONTEXT)
strcpy(description, "The specified window has no context");
else if (code == GLFW_CURSOR_UNAVAILABLE)
strcpy(description, "The specified cursor shape is unavailable");
else
strcpy(description, "ERROR: UNKNOWN GLFW ERROR");
}

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -755,9 +757,13 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape)
if (shape != GLFW_ARROW_CURSOR &&
shape != GLFW_IBEAM_CURSOR &&
shape != GLFW_CROSSHAIR_CURSOR &&
shape != GLFW_HAND_CURSOR &&
shape != GLFW_HRESIZE_CURSOR &&
shape != GLFW_VRESIZE_CURSOR)
shape != GLFW_POINTING_HAND_CURSOR &&
shape != GLFW_RESIZE_EW_CURSOR &&
shape != GLFW_RESIZE_NS_CURSOR &&
shape != GLFW_RESIZE_NWSE_CURSOR &&
shape != GLFW_RESIZE_NESW_CURSOR &&
shape != GLFW_RESIZE_ALL_CURSOR &&
shape != GLFW_NOT_ALLOWED_CURSOR)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape);
return NULL;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -84,8 +84,8 @@ typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*);
typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*);
#define GL_VERSION 0x1f02
#define GL_NONE 0
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_NONE 0
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_UNSIGNED_BYTE 0x1401
#define GL_EXTENSIONS 0x1f03
#define GL_NUM_EXTENSIONS 0x821d
@ -102,7 +102,7 @@ typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*);
#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82fc
#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008
typedef int GLint;
typedef int GLint;
typedef unsigned int GLuint;
typedef unsigned int GLenum;
typedef unsigned int GLbitfield;
@ -128,6 +128,7 @@ typedef enum VkStructureType
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000,
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
} VkStructureType;
@ -274,6 +275,9 @@ struct _GLFWwndconfig
char className[256];
char instanceName[256];
} x11;
struct {
GLFWbool keymenu;
} win32;
};
// Context configuration
@ -556,6 +560,7 @@ struct _GLFWlibrary
GLFWbool KHR_win32_surface;
#elif defined(_GLFW_COCOA)
GLFWbool MVK_macos_surface;
GLFWbool EXT_metal_surface;
#elif defined(_GLFW_X11)
GLFWbool KHR_xlib_surface;
GLFWbool KHR_xcb_surface;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
// GLFW 3.4 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -104,9 +106,7 @@ static void handleAbsEvent(_GLFWjoystick* js, int code, int value)
//
static void pollAbsState(_GLFWjoystick* js)
{
int code;
for (code = 0; code < ABS_CNT; code++)
for (int code = 0; code < ABS_CNT; code++)
{
if (js->linjs.absMap[code] < 0)
continue;
@ -126,18 +126,7 @@ static void pollAbsState(_GLFWjoystick* js)
//
static GLFWbool openJoystickDevice(const char* path)
{
int jid, code;
char name[256] = "";
char guid[33] = "";
char evBits[(EV_CNT + 7) / 8] = {0};
char keyBits[(KEY_CNT + 7) / 8] = {0};
char absBits[(ABS_CNT + 7) / 8] = {0};
int axisCount = 0, buttonCount = 0, hatCount = 0;
struct input_id id;
_GLFWjoystickLinux linjs = {0};
_GLFWjoystick* js = NULL;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.joysticks[jid].present)
continue;
@ -145,10 +134,16 @@ static GLFWbool openJoystickDevice(const char* path)
return GLFW_FALSE;
}
_GLFWjoystickLinux linjs = {0};
linjs.fd = open(path, O_RDONLY | O_NONBLOCK);
if (linjs.fd == -1)
return GLFW_FALSE;
char evBits[(EV_CNT + 7) / 8] = {0};
char keyBits[(KEY_CNT + 7) / 8] = {0};
char absBits[(ABS_CNT + 7) / 8] = {0};
struct input_id id;
if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
@ -168,9 +163,13 @@ static GLFWbool openJoystickDevice(const char* path)
return GLFW_FALSE;
}
char name[256] = "";
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
strncpy(name, "Unknown", sizeof(name));
char guid[33] = "";
// Generate a joystick GUID that matches the SDL 2.0.5+ one
if (id.vendor && id.product && id.version)
{
@ -189,7 +188,9 @@ static GLFWbool openJoystickDevice(const char* path)
name[8], name[9], name[10]);
}
for (code = BTN_MISC; code < KEY_CNT; code++)
int axisCount = 0, buttonCount = 0, hatCount = 0;
for (int code = BTN_MISC; code < KEY_CNT; code++)
{
if (!isBitSet(code, keyBits))
continue;
@ -198,7 +199,7 @@ static GLFWbool openJoystickDevice(const char* path)
buttonCount++;
}
for (code = 0; code < ABS_CNT; code++)
for (int code = 0; code < ABS_CNT; code++)
{
linjs.absMap[code] = -1;
if (!isBitSet(code, absBits))
@ -221,7 +222,8 @@ static GLFWbool openJoystickDevice(const char* path)
}
}
js = _glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
_GLFWjoystick* js =
_glfwAllocJoystick(name, guid, axisCount, buttonCount, hatCount);
if (!js)
{
close(linjs.fd);
@ -266,8 +268,6 @@ static int compareJoysticks(const void* fp, const void* sp)
//
GLFWbool _glfwInitJoysticksLinux(void)
{
DIR* dir;
int count = 0;
const char* dirname = "/dev/input";
_glfw.linjs.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
@ -289,7 +289,9 @@ GLFWbool _glfwInitJoysticksLinux(void)
return GLFW_FALSE;
}
dir = opendir(dirname);
int count = 0;
DIR* dir = opendir(dirname);
if (dir)
{
struct dirent* entry;
@ -344,12 +346,11 @@ void _glfwTerminateJoysticksLinux(void)
void _glfwDetectJoystickConnectionLinux(void)
{
ssize_t offset = 0;
char buffer[16384];
if (_glfw.linjs.inotify <= 0)
return;
ssize_t offset = 0;
char buffer[16384];
const ssize_t size = read(_glfw.linjs.inotify, buffer, sizeof(buffer));
while (size > offset)
@ -369,9 +370,7 @@ void _glfwDetectJoystickConnectionLinux(void)
openJoystickDevice(path);
else if (e->mask & IN_DELETE)
{
int jid;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
{

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
// GLFW 3.4 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
//
@ -84,7 +84,6 @@ const char* _glfwDefaultMappings[] =
"030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
"78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,",
"03000000790000000600000000000000,G-Shark GS-GP702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,",
"03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,",
"030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
"03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,",
@ -207,7 +206,6 @@ const char* _glfwDefaultMappings[] =
"030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,",
"03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000790000000600000000000000,G-Shark GP-702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,",
"030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,",

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -54,6 +56,10 @@ static int compareVideoModes(const void* fp, const void* sp)
if (farea != sarea)
return farea - sarea;
// Then sort on width
if (fm->width != sm->width)
return fm->width - sm->width;
// Lastly sort on refresh rate
return fm->refreshRate - sm->refreshRate;
}

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@ -24,6 +24,9 @@
//
//========================================================================
// NOTE: Many Cocoa enum values have been renamed and we need to build across
// SDK versions where one is unavailable or the other deprecated
// We use the newer names in code and these macros to handle compatibility
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101400
#define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
@ -41,10 +44,6 @@ typedef struct _GLFWcontextNSGL
{
id pixelFormat;
id object;
CVDisplayLinkRef displayLink;
atomic_int swapInterval;
int swapIntervalsPassed;
id swapIntervalCond;
} _GLFWcontextNSGL;
@ -64,5 +63,4 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
void _glfwDestroyContextNSGL(_GLFWwindow* window);
void _glfwUpdateDisplayLinkDisplayNSGL(_GLFWwindow* window);

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@ -23,32 +23,13 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
// Display link callback for manual swap interval implementation
// This is based on a similar workaround added to SDL2
//
static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink,
const CVTimeStamp* now,
const CVTimeStamp* outputTime,
CVOptionFlags flagsIn,
CVOptionFlags* flagsOut,
void* userInfo)
{
_GLFWwindow* window = (_GLFWwindow *) userInfo;
const int interval = atomic_load(&window->context.nsgl.swapInterval);
if (interval > 0)
{
[window->context.nsgl.swapIntervalCond lock];
window->context.nsgl.swapIntervalsPassed++;
[window->context.nsgl.swapIntervalCond signal];
[window->context.nsgl.swapIntervalCond unlock];
}
return kCVReturnSuccess;
}
#include <unistd.h>
#include <math.h>
static void makeContextCurrentNSGL(_GLFWwindow* window)
{
@ -68,19 +49,28 @@ static void swapBuffersNSGL(_GLFWwindow* window)
{
@autoreleasepool {
const int interval = atomic_load(&window->context.nsgl.swapInterval);
if (interval > 0)
// HACK: Simulate vsync with usleep as NSGL swap interval does not apply to
// windows with a non-visible occlusion state
if (!([window->ns.object occlusionState] & NSWindowOcclusionStateVisible))
{
[window->context.nsgl.swapIntervalCond lock];
do
int interval = 0;
[window->context.nsgl.object getValues:&interval
forParameter:NSOpenGLContextParameterSwapInterval];
if (interval > 0)
{
[window->context.nsgl.swapIntervalCond wait];
} while (window->context.nsgl.swapIntervalsPassed % interval != 0);
window->context.nsgl.swapIntervalsPassed = 0;
[window->context.nsgl.swapIntervalCond unlock];
const double framerate = 60.0;
const uint64_t frequency = _glfwPlatformGetTimerFrequency();
const uint64_t value = _glfwPlatformGetTimerValue();
const double elapsed = value / (double) frequency;
const double period = 1.0 / framerate;
const double delay = period - fmod(elapsed, period);
usleep(floorl(delay * 1e6));
}
}
// ARP appears to be unnecessary, but this is future-proof
[window->context.nsgl.object flushBuffer];
} // autoreleasepool
@ -89,11 +79,14 @@ static void swapBuffersNSGL(_GLFWwindow* window)
static void swapIntervalNSGL(int interval)
{
@autoreleasepool {
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
atomic_store(&window->context.nsgl.swapInterval, interval);
[window->context.nsgl.swapIntervalCond lock];
window->context.nsgl.swapIntervalsPassed = 0;
[window->context.nsgl.swapIntervalCond unlock];
if (window)
{
[window->context.nsgl.object setValues:&interval
forParameter:NSOpenGLContextParameterSwapInterval];
}
} // autoreleasepool
}
@ -117,23 +110,10 @@ static GLFWglproc getProcAddressNSGL(const char* procname)
return symbol;
}
// Destroy the OpenGL context
//
static void destroyContextNSGL(_GLFWwindow* window)
{
@autoreleasepool {
if (window->context.nsgl.displayLink)
{
if (CVDisplayLinkIsRunning(window->context.nsgl.displayLink))
CVDisplayLinkStop(window->context.nsgl.displayLink);
CVDisplayLinkRelease(window->context.nsgl.displayLink);
}
[window->context.nsgl.swapIntervalCond release];
window->context.nsgl.swapIntervalCond = nil;
[window->context.nsgl.pixelFormat release];
window->context.nsgl.pixelFormat = nil;
@ -194,13 +174,6 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
"NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above");
return GLFW_FALSE;
}
if (!ctxconfig->forward || ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"NSGL: The targeted version of macOS only supports forward-compatible core profile contexts for OpenGL 3.2 and above");
return GLFW_FALSE;
}
}
// Context robustness modes (GL_KHR_robustness) are not yet supported by
@ -339,7 +312,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
return GLFW_FALSE;
}
NSOpenGLContext* share = NULL;
NSOpenGLContext* share = nil;
if (ctxconfig->share)
share = ctxconfig->share->context.nsgl.object;
@ -361,17 +334,10 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
forParameter:NSOpenGLContextParameterSurfaceOpacity];
}
if (window->ns.retina)
[window->ns.view setWantsBestResolutionOpenGLSurface:YES];
GLint interval = 0;
[window->context.nsgl.object setValues:&interval
forParameter:NSOpenGLContextParameterSwapInterval];
[window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina];
[window->context.nsgl.object setView:window->ns.view];
window->context.nsgl.swapIntervalCond = [NSCondition new];
window->context.makeCurrent = makeContextCurrentNSGL;
window->context.swapBuffers = swapBuffersNSGL;
window->context.swapInterval = swapIntervalNSGL;
@ -379,26 +345,9 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
window->context.getProcAddress = getProcAddressNSGL;
window->context.destroy = destroyContextNSGL;
CVDisplayLinkCreateWithActiveCGDisplays(&window->context.nsgl.displayLink);
CVDisplayLinkSetOutputCallback(window->context.nsgl.displayLink,
&displayLinkCallback,
window);
CVDisplayLinkStart(window->context.nsgl.displayLink);
_glfwUpdateDisplayLinkDisplayNSGL(window);
return GLFW_TRUE;
}
void _glfwUpdateDisplayLinkDisplayNSGL(_GLFWwindow* window)
{
CGDirectDisplayID displayID =
[[[window->ns.object screen] deviceDescription][@"NSScreenNumber"] unsignedIntValue];
if (!displayID)
return;
CVDisplayLinkSetCurrentCGDisplay(window->context.nsgl.displayLink, displayID);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
@ -412,7 +361,7 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL;
return nil;
}
return window->context.nsgl.object;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
//
@ -23,6 +23,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//
@ -24,8 +24,8 @@
//
//========================================================================
#define _GLFW_PLATFORM_JOYSTICK_STATE int nulljs
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int nulljs
#define _GLFW_PLATFORM_JOYSTICK_STATE struct { int dummyJoystick; }
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyLibraryJoystick; }
#define _GLFW_PLATFORM_MAPPING_NAME ""

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
@ -29,13 +29,13 @@
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNull null
#define _GLFW_PLATFORM_CONTEXT_STATE
#define _GLFW_PLATFORM_MONITOR_STATE
#define _GLFW_PLATFORM_CURSOR_STATE
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
#define _GLFW_EGL_CONTEXT_STATE
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE
#define _GLFW_PLATFORM_CONTEXT_STATE struct { int dummyContext; }
#define _GLFW_PLATFORM_MONITOR_STATE struct { int dummyMonitor; }
#define _GLFW_PLATFORM_CURSOR_STATE struct { int dummyCursor; }
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE struct { int dummyLibraryWindow; }
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE struct { int dummyLibraryContext; }
#define _GLFW_EGL_CONTEXT_STATE struct { int dummyEGLContext; }
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE struct { int dummyEGLLibraryContext; }
#include "osmesa_context.h"
#include "posix_time.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
// GLFW 3.4 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include <stdlib.h>
#include <string.h>

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
// GLFW 3.4 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@ -24,9 +24,14 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
//#define _POSIX_C_SOURCE 199309L
#include "internal.h"
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
@ -39,7 +44,7 @@
//
void _glfwInitTimerPOSIX(void)
{
#if defined(CLOCK_MONOTONIC)
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
@ -62,7 +67,7 @@ void _glfwInitTimerPOSIX(void)
uint64_t _glfwPlatformGetTimerValue(void)
{
#if defined(CLOCK_MONOTONIC)
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
if (_glfw.timer.posix.monotonic)
{
struct timespec ts;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -55,6 +57,8 @@ GLFWbool _glfwInitVulkan(int mode)
_glfw.vk.handle = _glfw_dlopen("vulkan-1.dll");
#elif defined(_GLFW_COCOA)
_glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
if (!_glfw.vk.handle)
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS();
#else
_glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
#endif
@ -128,6 +132,8 @@ GLFWbool _glfwInitVulkan(int mode)
#elif defined(_GLFW_COCOA)
else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
_glfw.vk.MVK_macos_surface = GLFW_TRUE;
else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0)
_glfw.vk.EXT_metal_surface = GLFW_TRUE;
#elif defined(_GLFW_X11)
else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
_glfw.vk.KHR_xlib_surface = GLFW_TRUE;

View file

@ -0,0 +1,58 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2015 Samsung Electronics Co., Ltd
*
* 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 (including the next
* paragraph) 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface zwp_idle_inhibitor_v1_interface;
static const struct wl_interface *idle_inhibit_unstable_v1_wl_ii_types[] = {
&zwp_idle_inhibitor_v1_interface,
&wl_surface_interface,
};
static const struct wl_message zwp_idle_inhibit_manager_v1_requests[] = {
{ "destroy", "", idle_inhibit_unstable_v1_wl_ii_types + 0 },
{ "create_inhibitor", "no", idle_inhibit_unstable_v1_wl_ii_types + 0 },
};
WL_EXPORT const struct wl_interface zwp_idle_inhibit_manager_v1_interface = {
"zwp_idle_inhibit_manager_v1", 1,
2, zwp_idle_inhibit_manager_v1_requests,
0, NULL,
};
static const struct wl_message zwp_idle_inhibitor_v1_requests[] = {
{ "destroy", "", idle_inhibit_unstable_v1_wl_ii_types + 0 },
};
WL_EXPORT const struct wl_interface zwp_idle_inhibitor_v1_interface = {
"zwp_idle_inhibitor_v1", 1,
1, zwp_idle_inhibitor_v1_requests,
0, NULL,
};

View file

@ -0,0 +1,230 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_idle_inhibit_unstable_v1 The idle_inhibit_unstable_v1 protocol
* @section page_ifaces_idle_inhibit_unstable_v1 Interfaces
* - @subpage page_iface_zwp_idle_inhibit_manager_v1 - control behavior when display idles
* - @subpage page_iface_zwp_idle_inhibitor_v1 - context object for inhibiting idle behavior
* @section page_copyright_idle_inhibit_unstable_v1 Copyright
* <pre>
*
* Copyright © 2015 Samsung Electronics Co., Ltd
*
* 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 (including the next
* paragraph) 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.
* </pre>
*/
struct wl_surface;
struct zwp_idle_inhibit_manager_v1;
struct zwp_idle_inhibitor_v1;
/**
* @page page_iface_zwp_idle_inhibit_manager_v1 zwp_idle_inhibit_manager_v1
* @section page_iface_zwp_idle_inhibit_manager_v1_desc Description
*
* This interface permits inhibiting the idle behavior such as screen
* blanking, locking, and screensaving. The client binds the idle manager
* globally, then creates idle-inhibitor objects for each surface.
*
* Warning! The protocol described in this file is experimental and
* backward incompatible changes may be made. Backward compatible changes
* may be added together with the corresponding interface version bump.
* Backward incompatible changes are done by bumping the version number in
* the protocol and interface names and resetting the interface version.
* Once the protocol is to be declared stable, the 'z' prefix and the
* version number in the protocol and interface names are removed and the
* interface version number is reset.
* @section page_iface_zwp_idle_inhibit_manager_v1_api API
* See @ref iface_zwp_idle_inhibit_manager_v1.
*/
/**
* @defgroup iface_zwp_idle_inhibit_manager_v1 The zwp_idle_inhibit_manager_v1 interface
*
* This interface permits inhibiting the idle behavior such as screen
* blanking, locking, and screensaving. The client binds the idle manager
* globally, then creates idle-inhibitor objects for each surface.
*
* Warning! The protocol described in this file is experimental and
* backward incompatible changes may be made. Backward compatible changes
* may be added together with the corresponding interface version bump.
* Backward incompatible changes are done by bumping the version number in
* the protocol and interface names and resetting the interface version.
* Once the protocol is to be declared stable, the 'z' prefix and the
* version number in the protocol and interface names are removed and the
* interface version number is reset.
*/
extern const struct wl_interface zwp_idle_inhibit_manager_v1_interface;
/**
* @page page_iface_zwp_idle_inhibitor_v1 zwp_idle_inhibitor_v1
* @section page_iface_zwp_idle_inhibitor_v1_desc Description
*
* An idle inhibitor prevents the output that the associated surface is
* visible on from being set to a state where it is not visually usable due
* to lack of user interaction (e.g. blanked, dimmed, locked, set to power
* save, etc.) Any screensaver processes are also blocked from displaying.
*
* If the surface is destroyed, unmapped, becomes occluded, loses
* visibility, or otherwise becomes not visually relevant for the user, the
* idle inhibitor will not be honored by the compositor; if the surface
* subsequently regains visibility the inhibitor takes effect once again.
* Likewise, the inhibitor isn't honored if the system was already idled at
* the time the inhibitor was established, although if the system later
* de-idles and re-idles the inhibitor will take effect.
* @section page_iface_zwp_idle_inhibitor_v1_api API
* See @ref iface_zwp_idle_inhibitor_v1.
*/
/**
* @defgroup iface_zwp_idle_inhibitor_v1 The zwp_idle_inhibitor_v1 interface
*
* An idle inhibitor prevents the output that the associated surface is
* visible on from being set to a state where it is not visually usable due
* to lack of user interaction (e.g. blanked, dimmed, locked, set to power
* save, etc.) Any screensaver processes are also blocked from displaying.
*
* If the surface is destroyed, unmapped, becomes occluded, loses
* visibility, or otherwise becomes not visually relevant for the user, the
* idle inhibitor will not be honored by the compositor; if the surface
* subsequently regains visibility the inhibitor takes effect once again.
* Likewise, the inhibitor isn't honored if the system was already idled at
* the time the inhibitor was established, although if the system later
* de-idles and re-idles the inhibitor will take effect.
*/
extern const struct wl_interface zwp_idle_inhibitor_v1_interface;
#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY 0
#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR 1
/**
* @ingroup iface_zwp_idle_inhibit_manager_v1
*/
#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zwp_idle_inhibit_manager_v1
*/
#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR_SINCE_VERSION 1
/** @ingroup iface_zwp_idle_inhibit_manager_v1 */
static inline void
zwp_idle_inhibit_manager_v1_set_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1, user_data);
}
/** @ingroup iface_zwp_idle_inhibit_manager_v1 */
static inline void *
zwp_idle_inhibit_manager_v1_get_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
}
static inline uint32_t
zwp_idle_inhibit_manager_v1_get_version(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
}
/**
* @ingroup iface_zwp_idle_inhibit_manager_v1
*
* Destroy the inhibit manager.
*/
static inline void
zwp_idle_inhibit_manager_v1_destroy(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwp_idle_inhibit_manager_v1,
ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwp_idle_inhibit_manager_v1);
}
/**
* @ingroup iface_zwp_idle_inhibit_manager_v1
*
* Create a new inhibitor object associated with the given surface.
*/
static inline struct zwp_idle_inhibitor_v1 *
zwp_idle_inhibit_manager_v1_create_inhibitor(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, struct wl_surface *surface)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_idle_inhibit_manager_v1,
ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR, &zwp_idle_inhibitor_v1_interface, NULL, surface);
return (struct zwp_idle_inhibitor_v1 *) id;
}
#define ZWP_IDLE_INHIBITOR_V1_DESTROY 0
/**
* @ingroup iface_zwp_idle_inhibitor_v1
*/
#define ZWP_IDLE_INHIBITOR_V1_DESTROY_SINCE_VERSION 1
/** @ingroup iface_zwp_idle_inhibitor_v1 */
static inline void
zwp_idle_inhibitor_v1_set_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1, user_data);
}
/** @ingroup iface_zwp_idle_inhibitor_v1 */
static inline void *
zwp_idle_inhibitor_v1_get_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1);
}
static inline uint32_t
zwp_idle_inhibitor_v1_get_version(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1);
}
/**
* @ingroup iface_zwp_idle_inhibitor_v1
*
* Remove the inhibitor effect from the associated wl_surface.
*/
static inline void
zwp_idle_inhibitor_v1_destroy(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwp_idle_inhibitor_v1,
ZWP_IDLE_INHIBITOR_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwp_idle_inhibitor_v1);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,98 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2014 Jonas Ådahl
* Copyright © 2015 Red Hat Inc.
*
* 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 (including the next
* paragraph) 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_pointer_interface;
extern const struct wl_interface wl_region_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface zwp_confined_pointer_v1_interface;
extern const struct wl_interface zwp_locked_pointer_v1_interface;
static const struct wl_interface *pointer_constraints_unstable_v1_wl_pc_types[] = {
NULL,
NULL,
&zwp_locked_pointer_v1_interface,
&wl_surface_interface,
&wl_pointer_interface,
&wl_region_interface,
NULL,
&zwp_confined_pointer_v1_interface,
&wl_surface_interface,
&wl_pointer_interface,
&wl_region_interface,
NULL,
&wl_region_interface,
&wl_region_interface,
};
static const struct wl_message zwp_pointer_constraints_v1_requests[] = {
{ "destroy", "", pointer_constraints_unstable_v1_wl_pc_types + 0 },
{ "lock_pointer", "noo?ou", pointer_constraints_unstable_v1_wl_pc_types + 2 },
{ "confine_pointer", "noo?ou", pointer_constraints_unstable_v1_wl_pc_types + 7 },
};
WL_EXPORT const struct wl_interface zwp_pointer_constraints_v1_interface = {
"zwp_pointer_constraints_v1", 1,
3, zwp_pointer_constraints_v1_requests,
0, NULL,
};
static const struct wl_message zwp_locked_pointer_v1_requests[] = {
{ "destroy", "", pointer_constraints_unstable_v1_wl_pc_types + 0 },
{ "set_cursor_position_hint", "ff", pointer_constraints_unstable_v1_wl_pc_types + 0 },
{ "set_region", "?o", pointer_constraints_unstable_v1_wl_pc_types + 12 },
};
static const struct wl_message zwp_locked_pointer_v1_events[] = {
{ "locked", "", pointer_constraints_unstable_v1_wl_pc_types + 0 },
{ "unlocked", "", pointer_constraints_unstable_v1_wl_pc_types + 0 },
};
WL_EXPORT const struct wl_interface zwp_locked_pointer_v1_interface = {
"zwp_locked_pointer_v1", 1,
3, zwp_locked_pointer_v1_requests,
2, zwp_locked_pointer_v1_events,
};
static const struct wl_message zwp_confined_pointer_v1_requests[] = {
{ "destroy", "", pointer_constraints_unstable_v1_wl_pc_types + 0 },
{ "set_region", "?o", pointer_constraints_unstable_v1_wl_pc_types + 13 },
};
static const struct wl_message zwp_confined_pointer_v1_events[] = {
{ "confined", "", pointer_constraints_unstable_v1_wl_pc_types + 0 },
{ "unconfined", "", pointer_constraints_unstable_v1_wl_pc_types + 0 },
};
WL_EXPORT const struct wl_interface zwp_confined_pointer_v1_interface = {
"zwp_confined_pointer_v1", 1,
2, zwp_confined_pointer_v1_requests,
2, zwp_confined_pointer_v1_events,
};

View file

@ -0,0 +1,649 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_pointer_constraints_unstable_v1 The pointer_constraints_unstable_v1 protocol
* protocol for constraining pointer motions
*
* @section page_desc_pointer_constraints_unstable_v1 Description
*
* This protocol specifies a set of interfaces used for adding constraints to
* the motion of a pointer. Possible constraints include confining pointer
* motions to a given region, or locking it to its current position.
*
* In order to constrain the pointer, a client must first bind the global
* interface "wp_pointer_constraints" which, if a compositor supports pointer
* constraints, is exposed by the registry. Using the bound global object, the
* client uses the request that corresponds to the type of constraint it wants
* to make. See wp_pointer_constraints for more details.
*
* Warning! The protocol described in this file is experimental and backward
* incompatible changes may be made. Backward compatible changes may be added
* together with the corresponding interface version bump. Backward
* incompatible changes are done by bumping the version number in the protocol
* and interface names and resetting the interface version. Once the protocol
* is to be declared stable, the 'z' prefix and the version number in the
* protocol and interface names are removed and the interface version number is
* reset.
*
* @section page_ifaces_pointer_constraints_unstable_v1 Interfaces
* - @subpage page_iface_zwp_pointer_constraints_v1 - constrain the movement of a pointer
* - @subpage page_iface_zwp_locked_pointer_v1 - receive relative pointer motion events
* - @subpage page_iface_zwp_confined_pointer_v1 - confined pointer object
* @section page_copyright_pointer_constraints_unstable_v1 Copyright
* <pre>
*
* Copyright © 2014 Jonas Ådahl
* Copyright © 2015 Red Hat Inc.
*
* 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 (including the next
* paragraph) 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.
* </pre>
*/
struct wl_pointer;
struct wl_region;
struct wl_surface;
struct zwp_confined_pointer_v1;
struct zwp_locked_pointer_v1;
struct zwp_pointer_constraints_v1;
/**
* @page page_iface_zwp_pointer_constraints_v1 zwp_pointer_constraints_v1
* @section page_iface_zwp_pointer_constraints_v1_desc Description
*
* The global interface exposing pointer constraining functionality. It
* exposes two requests: lock_pointer for locking the pointer to its
* position, and confine_pointer for locking the pointer to a region.
*
* The lock_pointer and confine_pointer requests create the objects
* wp_locked_pointer and wp_confined_pointer respectively, and the client can
* use these objects to interact with the lock.
*
* For any surface, only one lock or confinement may be active across all
* wl_pointer objects of the same seat. If a lock or confinement is requested
* when another lock or confinement is active or requested on the same surface
* and with any of the wl_pointer objects of the same seat, an
* 'already_constrained' error will be raised.
* @section page_iface_zwp_pointer_constraints_v1_api API
* See @ref iface_zwp_pointer_constraints_v1.
*/
/**
* @defgroup iface_zwp_pointer_constraints_v1 The zwp_pointer_constraints_v1 interface
*
* The global interface exposing pointer constraining functionality. It
* exposes two requests: lock_pointer for locking the pointer to its
* position, and confine_pointer for locking the pointer to a region.
*
* The lock_pointer and confine_pointer requests create the objects
* wp_locked_pointer and wp_confined_pointer respectively, and the client can
* use these objects to interact with the lock.
*
* For any surface, only one lock or confinement may be active across all
* wl_pointer objects of the same seat. If a lock or confinement is requested
* when another lock or confinement is active or requested on the same surface
* and with any of the wl_pointer objects of the same seat, an
* 'already_constrained' error will be raised.
*/
extern const struct wl_interface zwp_pointer_constraints_v1_interface;
/**
* @page page_iface_zwp_locked_pointer_v1 zwp_locked_pointer_v1
* @section page_iface_zwp_locked_pointer_v1_desc Description
*
* The wp_locked_pointer interface represents a locked pointer state.
*
* While the lock of this object is active, the wl_pointer objects of the
* associated seat will not emit any wl_pointer.motion events.
*
* This object will send the event 'locked' when the lock is activated.
* Whenever the lock is activated, it is guaranteed that the locked surface
* will already have received pointer focus and that the pointer will be
* within the region passed to the request creating this object.
*
* To unlock the pointer, send the destroy request. This will also destroy
* the wp_locked_pointer object.
*
* If the compositor decides to unlock the pointer the unlocked event is
* sent. See wp_locked_pointer.unlock for details.
*
* When unlocking, the compositor may warp the cursor position to the set
* cursor position hint. If it does, it will not result in any relative
* motion events emitted via wp_relative_pointer.
*
* If the surface the lock was requested on is destroyed and the lock is not
* yet activated, the wp_locked_pointer object is now defunct and must be
* destroyed.
* @section page_iface_zwp_locked_pointer_v1_api API
* See @ref iface_zwp_locked_pointer_v1.
*/
/**
* @defgroup iface_zwp_locked_pointer_v1 The zwp_locked_pointer_v1 interface
*
* The wp_locked_pointer interface represents a locked pointer state.
*
* While the lock of this object is active, the wl_pointer objects of the
* associated seat will not emit any wl_pointer.motion events.
*
* This object will send the event 'locked' when the lock is activated.
* Whenever the lock is activated, it is guaranteed that the locked surface
* will already have received pointer focus and that the pointer will be
* within the region passed to the request creating this object.
*
* To unlock the pointer, send the destroy request. This will also destroy
* the wp_locked_pointer object.
*
* If the compositor decides to unlock the pointer the unlocked event is
* sent. See wp_locked_pointer.unlock for details.
*
* When unlocking, the compositor may warp the cursor position to the set
* cursor position hint. If it does, it will not result in any relative
* motion events emitted via wp_relative_pointer.
*
* If the surface the lock was requested on is destroyed and the lock is not
* yet activated, the wp_locked_pointer object is now defunct and must be
* destroyed.
*/
extern const struct wl_interface zwp_locked_pointer_v1_interface;
/**
* @page page_iface_zwp_confined_pointer_v1 zwp_confined_pointer_v1
* @section page_iface_zwp_confined_pointer_v1_desc Description
*
* The wp_confined_pointer interface represents a confined pointer state.
*
* This object will send the event 'confined' when the confinement is
* activated. Whenever the confinement is activated, it is guaranteed that
* the surface the pointer is confined to will already have received pointer
* focus and that the pointer will be within the region passed to the request
* creating this object. It is up to the compositor to decide whether this
* requires some user interaction and if the pointer will warp to within the
* passed region if outside.
*
* To unconfine the pointer, send the destroy request. This will also destroy
* the wp_confined_pointer object.
*
* If the compositor decides to unconfine the pointer the unconfined event is
* sent. The wp_confined_pointer object is at this point defunct and should
* be destroyed.
* @section page_iface_zwp_confined_pointer_v1_api API
* See @ref iface_zwp_confined_pointer_v1.
*/
/**
* @defgroup iface_zwp_confined_pointer_v1 The zwp_confined_pointer_v1 interface
*
* The wp_confined_pointer interface represents a confined pointer state.
*
* This object will send the event 'confined' when the confinement is
* activated. Whenever the confinement is activated, it is guaranteed that
* the surface the pointer is confined to will already have received pointer
* focus and that the pointer will be within the region passed to the request
* creating this object. It is up to the compositor to decide whether this
* requires some user interaction and if the pointer will warp to within the
* passed region if outside.
*
* To unconfine the pointer, send the destroy request. This will also destroy
* the wp_confined_pointer object.
*
* If the compositor decides to unconfine the pointer the unconfined event is
* sent. The wp_confined_pointer object is at this point defunct and should
* be destroyed.
*/
extern const struct wl_interface zwp_confined_pointer_v1_interface;
#ifndef ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
#define ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
/**
* @ingroup iface_zwp_pointer_constraints_v1
* wp_pointer_constraints error values
*
* These errors can be emitted in response to wp_pointer_constraints
* requests.
*/
enum zwp_pointer_constraints_v1_error {
/**
* pointer constraint already requested on that surface
*/
ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED = 1,
};
#endif /* ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM */
#ifndef ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
#define ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
/**
* @ingroup iface_zwp_pointer_constraints_v1
* the pointer constraint may reactivate
*
* A persistent pointer constraint may again reactivate once it has
* been deactivated. See the corresponding deactivation event
* (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for
* details.
*/
enum zwp_pointer_constraints_v1_lifetime {
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT = 1,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT = 2,
};
#endif /* ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM */
#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY 0
#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER 1
#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER 2
/**
* @ingroup iface_zwp_pointer_constraints_v1
*/
#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zwp_pointer_constraints_v1
*/
#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER_SINCE_VERSION 1
/**
* @ingroup iface_zwp_pointer_constraints_v1
*/
#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER_SINCE_VERSION 1
/** @ingroup iface_zwp_pointer_constraints_v1 */
static inline void
zwp_pointer_constraints_v1_set_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwp_pointer_constraints_v1, user_data);
}
/** @ingroup iface_zwp_pointer_constraints_v1 */
static inline void *
zwp_pointer_constraints_v1_get_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwp_pointer_constraints_v1);
}
static inline uint32_t
zwp_pointer_constraints_v1_get_version(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1);
}
/**
* @ingroup iface_zwp_pointer_constraints_v1
*
* Used by the client to notify the server that it will no longer use this
* pointer constraints object.
*/
static inline void
zwp_pointer_constraints_v1_destroy(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwp_pointer_constraints_v1,
ZWP_POINTER_CONSTRAINTS_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwp_pointer_constraints_v1);
}
/**
* @ingroup iface_zwp_pointer_constraints_v1
*
* The lock_pointer request lets the client request to disable movements of
* the virtual pointer (i.e. the cursor), effectively locking the pointer
* to a position. This request may not take effect immediately; in the
* future, when the compositor deems implementation-specific constraints
* are satisfied, the pointer lock will be activated and the compositor
* sends a locked event.
*
* The protocol provides no guarantee that the constraints are ever
* satisfied, and does not require the compositor to send an error if the
* constraints cannot ever be satisfied. It is thus possible to request a
* lock that will never activate.
*
* There may not be another pointer constraint of any kind requested or
* active on the surface for any of the wl_pointer objects of the seat of
* the passed pointer when requesting a lock. If there is, an error will be
* raised. See general pointer lock documentation for more details.
*
* The intersection of the region passed with this request and the input
* region of the surface is used to determine where the pointer must be
* in order for the lock to activate. It is up to the compositor whether to
* warp the pointer or require some kind of user interaction for the lock
* to activate. If the region is null the surface input region is used.
*
* A surface may receive pointer focus without the lock being activated.
*
* The request creates a new object wp_locked_pointer which is used to
* interact with the lock as well as receive updates about its state. See
* the the description of wp_locked_pointer for further information.
*
* Note that while a pointer is locked, the wl_pointer objects of the
* corresponding seat will not emit any wl_pointer.motion events, but
* relative motion events will still be emitted via wp_relative_pointer
* objects of the same seat. wl_pointer.axis and wl_pointer.button events
* are unaffected.
*/
static inline struct zwp_locked_pointer_v1 *
zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_pointer_constraints_v1,
ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER, &zwp_locked_pointer_v1_interface, NULL, surface, pointer, region, lifetime);
return (struct zwp_locked_pointer_v1 *) id;
}
/**
* @ingroup iface_zwp_pointer_constraints_v1
*
* The confine_pointer request lets the client request to confine the
* pointer cursor to a given region. This request may not take effect
* immediately; in the future, when the compositor deems implementation-
* specific constraints are satisfied, the pointer confinement will be
* activated and the compositor sends a confined event.
*
* The intersection of the region passed with this request and the input
* region of the surface is used to determine where the pointer must be
* in order for the confinement to activate. It is up to the compositor
* whether to warp the pointer or require some kind of user interaction for
* the confinement to activate. If the region is null the surface input
* region is used.
*
* The request will create a new object wp_confined_pointer which is used
* to interact with the confinement as well as receive updates about its
* state. See the the description of wp_confined_pointer for further
* information.
*/
static inline struct zwp_confined_pointer_v1 *
zwp_pointer_constraints_v1_confine_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_pointer_constraints_v1,
ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER, &zwp_confined_pointer_v1_interface, NULL, surface, pointer, region, lifetime);
return (struct zwp_confined_pointer_v1 *) id;
}
/**
* @ingroup iface_zwp_locked_pointer_v1
* @struct zwp_locked_pointer_v1_listener
*/
struct zwp_locked_pointer_v1_listener {
/**
* lock activation event
*
* Notification that the pointer lock of the seat's pointer is
* activated.
*/
void (*locked)(void *data,
struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
/**
* lock deactivation event
*
* Notification that the pointer lock of the seat's pointer is no
* longer active. If this is a oneshot pointer lock (see
* wp_pointer_constraints.lifetime) this object is now defunct and
* should be destroyed. If this is a persistent pointer lock (see
* wp_pointer_constraints.lifetime) this pointer lock may again
* reactivate in the future.
*/
void (*unlocked)(void *data,
struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
};
/**
* @ingroup iface_zwp_locked_pointer_v1
*/
static inline int
zwp_locked_pointer_v1_add_listener(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1,
const struct zwp_locked_pointer_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zwp_locked_pointer_v1,
(void (**)(void)) listener, data);
}
#define ZWP_LOCKED_POINTER_V1_DESTROY 0
#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT 1
#define ZWP_LOCKED_POINTER_V1_SET_REGION 2
/**
* @ingroup iface_zwp_locked_pointer_v1
*/
#define ZWP_LOCKED_POINTER_V1_LOCKED_SINCE_VERSION 1
/**
* @ingroup iface_zwp_locked_pointer_v1
*/
#define ZWP_LOCKED_POINTER_V1_UNLOCKED_SINCE_VERSION 1
/**
* @ingroup iface_zwp_locked_pointer_v1
*/
#define ZWP_LOCKED_POINTER_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zwp_locked_pointer_v1
*/
#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT_SINCE_VERSION 1
/**
* @ingroup iface_zwp_locked_pointer_v1
*/
#define ZWP_LOCKED_POINTER_V1_SET_REGION_SINCE_VERSION 1
/** @ingroup iface_zwp_locked_pointer_v1 */
static inline void
zwp_locked_pointer_v1_set_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwp_locked_pointer_v1, user_data);
}
/** @ingroup iface_zwp_locked_pointer_v1 */
static inline void *
zwp_locked_pointer_v1_get_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwp_locked_pointer_v1);
}
static inline uint32_t
zwp_locked_pointer_v1_get_version(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1);
}
/**
* @ingroup iface_zwp_locked_pointer_v1
*
* Destroy the locked pointer object. If applicable, the compositor will
* unlock the pointer.
*/
static inline void
zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1,
ZWP_LOCKED_POINTER_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwp_locked_pointer_v1);
}
/**
* @ingroup iface_zwp_locked_pointer_v1
*
* Set the cursor position hint relative to the top left corner of the
* surface.
*
* If the client is drawing its own cursor, it should update the position
* hint to the position of its own cursor. A compositor may use this
* information to warp the pointer upon unlock in order to avoid pointer
* jumps.
*
* The cursor position hint is double buffered. The new hint will only take
* effect when the associated surface gets it pending state applied. See
* wl_surface.commit for details.
*/
static inline void
zwp_locked_pointer_v1_set_cursor_position_hint(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1,
ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT, surface_x, surface_y);
}
/**
* @ingroup iface_zwp_locked_pointer_v1
*
* Set a new region used to lock the pointer.
*
* The new lock region is double-buffered. The new lock region will
* only take effect when the associated surface gets its pending state
* applied. See wl_surface.commit for details.
*
* For details about the lock region, see wp_locked_pointer.
*/
static inline void
zwp_locked_pointer_v1_set_region(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, struct wl_region *region)
{
wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1,
ZWP_LOCKED_POINTER_V1_SET_REGION, region);
}
/**
* @ingroup iface_zwp_confined_pointer_v1
* @struct zwp_confined_pointer_v1_listener
*/
struct zwp_confined_pointer_v1_listener {
/**
* pointer confined
*
* Notification that the pointer confinement of the seat's
* pointer is activated.
*/
void (*confined)(void *data,
struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
/**
* pointer unconfined
*
* Notification that the pointer confinement of the seat's
* pointer is no longer active. If this is a oneshot pointer
* confinement (see wp_pointer_constraints.lifetime) this object is
* now defunct and should be destroyed. If this is a persistent
* pointer confinement (see wp_pointer_constraints.lifetime) this
* pointer confinement may again reactivate in the future.
*/
void (*unconfined)(void *data,
struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
};
/**
* @ingroup iface_zwp_confined_pointer_v1
*/
static inline int
zwp_confined_pointer_v1_add_listener(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1,
const struct zwp_confined_pointer_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zwp_confined_pointer_v1,
(void (**)(void)) listener, data);
}
#define ZWP_CONFINED_POINTER_V1_DESTROY 0
#define ZWP_CONFINED_POINTER_V1_SET_REGION 1
/**
* @ingroup iface_zwp_confined_pointer_v1
*/
#define ZWP_CONFINED_POINTER_V1_CONFINED_SINCE_VERSION 1
/**
* @ingroup iface_zwp_confined_pointer_v1
*/
#define ZWP_CONFINED_POINTER_V1_UNCONFINED_SINCE_VERSION 1
/**
* @ingroup iface_zwp_confined_pointer_v1
*/
#define ZWP_CONFINED_POINTER_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zwp_confined_pointer_v1
*/
#define ZWP_CONFINED_POINTER_V1_SET_REGION_SINCE_VERSION 1
/** @ingroup iface_zwp_confined_pointer_v1 */
static inline void
zwp_confined_pointer_v1_set_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwp_confined_pointer_v1, user_data);
}
/** @ingroup iface_zwp_confined_pointer_v1 */
static inline void *
zwp_confined_pointer_v1_get_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwp_confined_pointer_v1);
}
static inline uint32_t
zwp_confined_pointer_v1_get_version(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1);
}
/**
* @ingroup iface_zwp_confined_pointer_v1
*
* Destroy the confined pointer object. If applicable, the compositor will
* unconfine the pointer.
*/
static inline void
zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwp_confined_pointer_v1,
ZWP_CONFINED_POINTER_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwp_confined_pointer_v1);
}
/**
* @ingroup iface_zwp_confined_pointer_v1
*
* Set a new region used to confine the pointer.
*
* The new confine region is double-buffered. The new confine region will
* only take effect when the associated surface gets its pending state
* applied. See wl_surface.commit for details.
*
* If the confinement is active when the new confinement region is applied
* and the pointer ends up outside of newly applied region, the pointer may
* warped to a position within the new confinement region. If warped, a
* wl_pointer.motion event will be emitted, but no
* wp_relative_pointer.relative_motion event.
*
* The compositor may also, instead of using the new region, unconfine the
* pointer.
*
* For details about the confine region, see wp_confined_pointer.
*/
static inline void
zwp_confined_pointer_v1_set_region(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, struct wl_region *region)
{
wl_proxy_marshal((struct wl_proxy *) zwp_confined_pointer_v1,
ZWP_CONFINED_POINTER_V1_SET_REGION, region);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,69 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2014 Jonas Ådahl
* Copyright © 2015 Red Hat Inc.
*
* 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 (including the next
* paragraph) 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_pointer_interface;
extern const struct wl_interface zwp_relative_pointer_v1_interface;
static const struct wl_interface *relative_pointer_unstable_v1_wl_rp_types[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&zwp_relative_pointer_v1_interface,
&wl_pointer_interface,
};
static const struct wl_message zwp_relative_pointer_manager_v1_requests[] = {
{ "destroy", "", relative_pointer_unstable_v1_wl_rp_types + 0 },
{ "get_relative_pointer", "no", relative_pointer_unstable_v1_wl_rp_types + 6 },
};
WL_EXPORT const struct wl_interface zwp_relative_pointer_manager_v1_interface = {
"zwp_relative_pointer_manager_v1", 1,
2, zwp_relative_pointer_manager_v1_requests,
0, NULL,
};
static const struct wl_message zwp_relative_pointer_v1_requests[] = {
{ "destroy", "", relative_pointer_unstable_v1_wl_rp_types + 0 },
};
static const struct wl_message zwp_relative_pointer_v1_events[] = {
{ "relative_motion", "uuffff", relative_pointer_unstable_v1_wl_rp_types + 0 },
};
WL_EXPORT const struct wl_interface zwp_relative_pointer_v1_interface = {
"zwp_relative_pointer_v1", 1,
1, zwp_relative_pointer_v1_requests,
1, zwp_relative_pointer_v1_events,
};

View file

@ -0,0 +1,295 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_relative_pointer_unstable_v1 The relative_pointer_unstable_v1 protocol
* protocol for relative pointer motion events
*
* @section page_desc_relative_pointer_unstable_v1 Description
*
* This protocol specifies a set of interfaces used for making clients able to
* receive relative pointer events not obstructed by barriers (such as the
* monitor edge or other pointer barriers).
*
* To start receiving relative pointer events, a client must first bind the
* global interface "wp_relative_pointer_manager" which, if a compositor
* supports relative pointer motion events, is exposed by the registry. After
* having created the relative pointer manager proxy object, the client uses
* it to create the actual relative pointer object using the
* "get_relative_pointer" request given a wl_pointer. The relative pointer
* motion events will then, when applicable, be transmitted via the proxy of
* the newly created relative pointer object. See the documentation of the
* relative pointer interface for more details.
*
* Warning! The protocol described in this file is experimental and backward
* incompatible changes may be made. Backward compatible changes may be added
* together with the corresponding interface version bump. Backward
* incompatible changes are done by bumping the version number in the protocol
* and interface names and resetting the interface version. Once the protocol
* is to be declared stable, the 'z' prefix and the version number in the
* protocol and interface names are removed and the interface version number is
* reset.
*
* @section page_ifaces_relative_pointer_unstable_v1 Interfaces
* - @subpage page_iface_zwp_relative_pointer_manager_v1 - get relative pointer objects
* - @subpage page_iface_zwp_relative_pointer_v1 - relative pointer object
* @section page_copyright_relative_pointer_unstable_v1 Copyright
* <pre>
*
* Copyright © 2014 Jonas Ådahl
* Copyright © 2015 Red Hat Inc.
*
* 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 (including the next
* paragraph) 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.
* </pre>
*/
struct wl_pointer;
struct zwp_relative_pointer_manager_v1;
struct zwp_relative_pointer_v1;
/**
* @page page_iface_zwp_relative_pointer_manager_v1 zwp_relative_pointer_manager_v1
* @section page_iface_zwp_relative_pointer_manager_v1_desc Description
*
* A global interface used for getting the relative pointer object for a
* given pointer.
* @section page_iface_zwp_relative_pointer_manager_v1_api API
* See @ref iface_zwp_relative_pointer_manager_v1.
*/
/**
* @defgroup iface_zwp_relative_pointer_manager_v1 The zwp_relative_pointer_manager_v1 interface
*
* A global interface used for getting the relative pointer object for a
* given pointer.
*/
extern const struct wl_interface zwp_relative_pointer_manager_v1_interface;
/**
* @page page_iface_zwp_relative_pointer_v1 zwp_relative_pointer_v1
* @section page_iface_zwp_relative_pointer_v1_desc Description
*
* A wp_relative_pointer object is an extension to the wl_pointer interface
* used for emitting relative pointer events. It shares the same focus as
* wl_pointer objects of the same seat and will only emit events when it has
* focus.
* @section page_iface_zwp_relative_pointer_v1_api API
* See @ref iface_zwp_relative_pointer_v1.
*/
/**
* @defgroup iface_zwp_relative_pointer_v1 The zwp_relative_pointer_v1 interface
*
* A wp_relative_pointer object is an extension to the wl_pointer interface
* used for emitting relative pointer events. It shares the same focus as
* wl_pointer objects of the same seat and will only emit events when it has
* focus.
*/
extern const struct wl_interface zwp_relative_pointer_v1_interface;
#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY 0
#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER 1
/**
* @ingroup iface_zwp_relative_pointer_manager_v1
*/
#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zwp_relative_pointer_manager_v1
*/
#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER_SINCE_VERSION 1
/** @ingroup iface_zwp_relative_pointer_manager_v1 */
static inline void
zwp_relative_pointer_manager_v1_set_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1, user_data);
}
/** @ingroup iface_zwp_relative_pointer_manager_v1 */
static inline void *
zwp_relative_pointer_manager_v1_get_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1);
}
static inline uint32_t
zwp_relative_pointer_manager_v1_get_version(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1);
}
/**
* @ingroup iface_zwp_relative_pointer_manager_v1
*
* Used by the client to notify the server that it will no longer use this
* relative pointer manager object.
*/
static inline void
zwp_relative_pointer_manager_v1_destroy(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwp_relative_pointer_manager_v1,
ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwp_relative_pointer_manager_v1);
}
/**
* @ingroup iface_zwp_relative_pointer_manager_v1
*
* Create a relative pointer interface given a wl_pointer object. See the
* wp_relative_pointer interface for more details.
*/
static inline struct zwp_relative_pointer_v1 *
zwp_relative_pointer_manager_v1_get_relative_pointer(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, struct wl_pointer *pointer)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_relative_pointer_manager_v1,
ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER, &zwp_relative_pointer_v1_interface, NULL, pointer);
return (struct zwp_relative_pointer_v1 *) id;
}
/**
* @ingroup iface_zwp_relative_pointer_v1
* @struct zwp_relative_pointer_v1_listener
*/
struct zwp_relative_pointer_v1_listener {
/**
* relative pointer motion
*
* Relative x/y pointer motion from the pointer of the seat
* associated with this object.
*
* A relative motion is in the same dimension as regular wl_pointer
* motion events, except they do not represent an absolute
* position. For example, moving a pointer from (x, y) to (x', y')
* would have the equivalent relative motion (x' - x, y' - y). If a
* pointer motion caused the absolute pointer position to be
* clipped by for example the edge of the monitor, the relative
* motion is unaffected by the clipping and will represent the
* unclipped motion.
*
* This event also contains non-accelerated motion deltas. The
* non-accelerated delta is, when applicable, the regular pointer
* motion delta as it was before having applied motion acceleration
* and other transformations such as normalization.
*
* Note that the non-accelerated delta does not represent 'raw'
* events as they were read from some device. Pointer motion
* acceleration is device- and configuration-specific and
* non-accelerated deltas and accelerated deltas may have the same
* value on some devices.
*
* Relative motions are not coupled to wl_pointer.motion events,
* and can be sent in combination with such events, but also
* independently. There may also be scenarios where
* wl_pointer.motion is sent, but there is no relative motion. The
* order of an absolute and relative motion event originating from
* the same physical motion is not guaranteed.
*
* If the client needs button events or focus state, it can receive
* them from a wl_pointer object of the same seat that the
* wp_relative_pointer object is associated with.
* @param utime_hi high 32 bits of a 64 bit timestamp with microsecond granularity
* @param utime_lo low 32 bits of a 64 bit timestamp with microsecond granularity
* @param dx the x component of the motion vector
* @param dy the y component of the motion vector
* @param dx_unaccel the x component of the unaccelerated motion vector
* @param dy_unaccel the y component of the unaccelerated motion vector
*/
void (*relative_motion)(void *data,
struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
uint32_t utime_hi,
uint32_t utime_lo,
wl_fixed_t dx,
wl_fixed_t dy,
wl_fixed_t dx_unaccel,
wl_fixed_t dy_unaccel);
};
/**
* @ingroup iface_zwp_relative_pointer_v1
*/
static inline int
zwp_relative_pointer_v1_add_listener(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
const struct zwp_relative_pointer_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zwp_relative_pointer_v1,
(void (**)(void)) listener, data);
}
#define ZWP_RELATIVE_POINTER_V1_DESTROY 0
/**
* @ingroup iface_zwp_relative_pointer_v1
*/
#define ZWP_RELATIVE_POINTER_V1_RELATIVE_MOTION_SINCE_VERSION 1
/**
* @ingroup iface_zwp_relative_pointer_v1
*/
#define ZWP_RELATIVE_POINTER_V1_DESTROY_SINCE_VERSION 1
/** @ingroup iface_zwp_relative_pointer_v1 */
static inline void
zwp_relative_pointer_v1_set_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_v1, user_data);
}
/** @ingroup iface_zwp_relative_pointer_v1 */
static inline void *
zwp_relative_pointer_v1_get_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_v1);
}
static inline uint32_t
zwp_relative_pointer_v1_get_version(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1);
}
/**
* @ingroup iface_zwp_relative_pointer_v1
*/
static inline void
zwp_relative_pointer_v1_destroy(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
{
wl_proxy_marshal((struct wl_proxy *) zwp_relative_pointer_v1,
ZWP_RELATIVE_POINTER_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zwp_relative_pointer_v1);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,64 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2013-2016 Collabora, Ltd.
*
* 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 (including the next
* paragraph) 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface wp_viewport_interface;
static const struct wl_interface *viewporter_wl_v_types[] = {
NULL,
NULL,
NULL,
NULL,
&wp_viewport_interface,
&wl_surface_interface,
};
static const struct wl_message wp_viewporter_requests[] = {
{ "destroy", "", viewporter_wl_v_types + 0 },
{ "get_viewport", "no", viewporter_wl_v_types + 4 },
};
WL_EXPORT const struct wl_interface wp_viewporter_interface = {
"wp_viewporter", 1,
2, wp_viewporter_requests,
0, NULL,
};
static const struct wl_message wp_viewport_requests[] = {
{ "destroy", "", viewporter_wl_v_types + 0 },
{ "set_source", "ffff", viewporter_wl_v_types + 0 },
{ "set_destination", "ii", viewporter_wl_v_types + 0 },
};
WL_EXPORT const struct wl_interface wp_viewport_interface = {
"wp_viewport", 1,
3, wp_viewport_requests,
0, NULL,
};

View file

@ -0,0 +1,408 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef VIEWPORTER_CLIENT_PROTOCOL_H
#define VIEWPORTER_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_viewporter The viewporter protocol
* @section page_ifaces_viewporter Interfaces
* - @subpage page_iface_wp_viewporter - surface cropping and scaling
* - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface
* @section page_copyright_viewporter Copyright
* <pre>
*
* Copyright © 2013-2016 Collabora, Ltd.
*
* 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 (including the next
* paragraph) 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.
* </pre>
*/
struct wl_surface;
struct wp_viewport;
struct wp_viewporter;
/**
* @page page_iface_wp_viewporter wp_viewporter
* @section page_iface_wp_viewporter_desc Description
*
* The global interface exposing surface cropping and scaling
* capabilities is used to instantiate an interface extension for a
* wl_surface object. This extended interface will then allow
* cropping and scaling the surface contents, effectively
* disconnecting the direct relationship between the buffer and the
* surface size.
* @section page_iface_wp_viewporter_api API
* See @ref iface_wp_viewporter.
*/
/**
* @defgroup iface_wp_viewporter The wp_viewporter interface
*
* The global interface exposing surface cropping and scaling
* capabilities is used to instantiate an interface extension for a
* wl_surface object. This extended interface will then allow
* cropping and scaling the surface contents, effectively
* disconnecting the direct relationship between the buffer and the
* surface size.
*/
extern const struct wl_interface wp_viewporter_interface;
/**
* @page page_iface_wp_viewport wp_viewport
* @section page_iface_wp_viewport_desc Description
*
* An additional interface to a wl_surface object, which allows the
* client to specify the cropping and scaling of the surface
* contents.
*
* This interface works with two concepts: the source rectangle (src_x,
* src_y, src_width, src_height), and the destination size (dst_width,
* dst_height). The contents of the source rectangle are scaled to the
* destination size, and content outside the source rectangle is ignored.
* This state is double-buffered, and is applied on the next
* wl_surface.commit.
*
* The two parts of crop and scale state are independent: the source
* rectangle, and the destination size. Initially both are unset, that
* is, no scaling is applied. The whole of the current wl_buffer is
* used as the source, and the surface size is as defined in
* wl_surface.attach.
*
* If the destination size is set, it causes the surface size to become
* dst_width, dst_height. The source (rectangle) is scaled to exactly
* this size. This overrides whatever the attached wl_buffer size is,
* unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
* has no content and therefore no size. Otherwise, the size is always
* at least 1x1 in surface local coordinates.
*
* If the source rectangle is set, it defines what area of the wl_buffer is
* taken as the source. If the source rectangle is set and the destination
* size is not set, then src_width and src_height must be integers, and the
* surface size becomes the source rectangle size. This results in cropping
* without scaling. If src_width or src_height are not integers and
* destination size is not set, the bad_size protocol error is raised when
* the surface state is applied.
*
* The coordinate transformations from buffer pixel coordinates up to
* the surface-local coordinates happen in the following order:
* 1. buffer_transform (wl_surface.set_buffer_transform)
* 2. buffer_scale (wl_surface.set_buffer_scale)
* 3. crop and scale (wp_viewport.set*)
* This means, that the source rectangle coordinates of crop and scale
* are given in the coordinates after the buffer transform and scale,
* i.e. in the coordinates that would be the surface-local coordinates
* if the crop and scale was not applied.
*
* If src_x or src_y are negative, the bad_value protocol error is raised.
* Otherwise, if the source rectangle is partially or completely outside of
* the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
* when the surface state is applied. A NULL wl_buffer does not raise the
* out_of_buffer error.
*
* The x, y arguments of wl_surface.attach are applied as normal to
* the surface. They indicate how many pixels to remove from the
* surface size from the left and the top. In other words, they are
* still in the surface-local coordinate system, just like dst_width
* and dst_height are.
*
* If the wl_surface associated with the wp_viewport is destroyed,
* all wp_viewport requests except 'destroy' raise the protocol error
* no_surface.
*
* If the wp_viewport object is destroyed, the crop and scale
* state is removed from the wl_surface. The change will be applied
* on the next wl_surface.commit.
* @section page_iface_wp_viewport_api API
* See @ref iface_wp_viewport.
*/
/**
* @defgroup iface_wp_viewport The wp_viewport interface
*
* An additional interface to a wl_surface object, which allows the
* client to specify the cropping and scaling of the surface
* contents.
*
* This interface works with two concepts: the source rectangle (src_x,
* src_y, src_width, src_height), and the destination size (dst_width,
* dst_height). The contents of the source rectangle are scaled to the
* destination size, and content outside the source rectangle is ignored.
* This state is double-buffered, and is applied on the next
* wl_surface.commit.
*
* The two parts of crop and scale state are independent: the source
* rectangle, and the destination size. Initially both are unset, that
* is, no scaling is applied. The whole of the current wl_buffer is
* used as the source, and the surface size is as defined in
* wl_surface.attach.
*
* If the destination size is set, it causes the surface size to become
* dst_width, dst_height. The source (rectangle) is scaled to exactly
* this size. This overrides whatever the attached wl_buffer size is,
* unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
* has no content and therefore no size. Otherwise, the size is always
* at least 1x1 in surface local coordinates.
*
* If the source rectangle is set, it defines what area of the wl_buffer is
* taken as the source. If the source rectangle is set and the destination
* size is not set, then src_width and src_height must be integers, and the
* surface size becomes the source rectangle size. This results in cropping
* without scaling. If src_width or src_height are not integers and
* destination size is not set, the bad_size protocol error is raised when
* the surface state is applied.
*
* The coordinate transformations from buffer pixel coordinates up to
* the surface-local coordinates happen in the following order:
* 1. buffer_transform (wl_surface.set_buffer_transform)
* 2. buffer_scale (wl_surface.set_buffer_scale)
* 3. crop and scale (wp_viewport.set*)
* This means, that the source rectangle coordinates of crop and scale
* are given in the coordinates after the buffer transform and scale,
* i.e. in the coordinates that would be the surface-local coordinates
* if the crop and scale was not applied.
*
* If src_x or src_y are negative, the bad_value protocol error is raised.
* Otherwise, if the source rectangle is partially or completely outside of
* the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
* when the surface state is applied. A NULL wl_buffer does not raise the
* out_of_buffer error.
*
* The x, y arguments of wl_surface.attach are applied as normal to
* the surface. They indicate how many pixels to remove from the
* surface size from the left and the top. In other words, they are
* still in the surface-local coordinate system, just like dst_width
* and dst_height are.
*
* If the wl_surface associated with the wp_viewport is destroyed,
* all wp_viewport requests except 'destroy' raise the protocol error
* no_surface.
*
* If the wp_viewport object is destroyed, the crop and scale
* state is removed from the wl_surface. The change will be applied
* on the next wl_surface.commit.
*/
extern const struct wl_interface wp_viewport_interface;
#ifndef WP_VIEWPORTER_ERROR_ENUM
#define WP_VIEWPORTER_ERROR_ENUM
enum wp_viewporter_error {
/**
* the surface already has a viewport object associated
*/
WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0,
};
#endif /* WP_VIEWPORTER_ERROR_ENUM */
#define WP_VIEWPORTER_DESTROY 0
#define WP_VIEWPORTER_GET_VIEWPORT 1
/**
* @ingroup iface_wp_viewporter
*/
#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_wp_viewporter
*/
#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1
/** @ingroup iface_wp_viewporter */
static inline void
wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data);
}
/** @ingroup iface_wp_viewporter */
static inline void *
wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter)
{
return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter);
}
static inline uint32_t
wp_viewporter_get_version(struct wp_viewporter *wp_viewporter)
{
return wl_proxy_get_version((struct wl_proxy *) wp_viewporter);
}
/**
* @ingroup iface_wp_viewporter
*
* Informs the server that the client will not be using this
* protocol object anymore. This does not affect any other objects,
* wp_viewport objects included.
*/
static inline void
wp_viewporter_destroy(struct wp_viewporter *wp_viewporter)
{
wl_proxy_marshal((struct wl_proxy *) wp_viewporter,
WP_VIEWPORTER_DESTROY);
wl_proxy_destroy((struct wl_proxy *) wp_viewporter);
}
/**
* @ingroup iface_wp_viewporter
*
* Instantiate an interface extension for the given wl_surface to
* crop and scale its content. If the given wl_surface already has
* a wp_viewport object associated, the viewport_exists
* protocol error is raised.
*/
static inline struct wp_viewport *
wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) wp_viewporter,
WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, NULL, surface);
return (struct wp_viewport *) id;
}
#ifndef WP_VIEWPORT_ERROR_ENUM
#define WP_VIEWPORT_ERROR_ENUM
enum wp_viewport_error {
/**
* negative or zero values in width or height
*/
WP_VIEWPORT_ERROR_BAD_VALUE = 0,
/**
* destination size is not integer
*/
WP_VIEWPORT_ERROR_BAD_SIZE = 1,
/**
* source rectangle extends outside of the content area
*/
WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2,
/**
* the wl_surface was destroyed
*/
WP_VIEWPORT_ERROR_NO_SURFACE = 3,
};
#endif /* WP_VIEWPORT_ERROR_ENUM */
#define WP_VIEWPORT_DESTROY 0
#define WP_VIEWPORT_SET_SOURCE 1
#define WP_VIEWPORT_SET_DESTINATION 2
/**
* @ingroup iface_wp_viewport
*/
#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_wp_viewport
*/
#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1
/**
* @ingroup iface_wp_viewport
*/
#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1
/** @ingroup iface_wp_viewport */
static inline void
wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data);
}
/** @ingroup iface_wp_viewport */
static inline void *
wp_viewport_get_user_data(struct wp_viewport *wp_viewport)
{
return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport);
}
static inline uint32_t
wp_viewport_get_version(struct wp_viewport *wp_viewport)
{
return wl_proxy_get_version((struct wl_proxy *) wp_viewport);
}
/**
* @ingroup iface_wp_viewport
*
* The associated wl_surface's crop and scale state is removed.
* The change is applied on the next wl_surface.commit.
*/
static inline void
wp_viewport_destroy(struct wp_viewport *wp_viewport)
{
wl_proxy_marshal((struct wl_proxy *) wp_viewport,
WP_VIEWPORT_DESTROY);
wl_proxy_destroy((struct wl_proxy *) wp_viewport);
}
/**
* @ingroup iface_wp_viewport
*
* Set the source rectangle of the associated wl_surface. See
* wp_viewport for the description, and relation to the wl_buffer
* size.
*
* If all of x, y, width and height are -1.0, the source rectangle is
* unset instead. Any other set of values where width or height are zero
* or negative, or x or y are negative, raise the bad_value protocol
* error.
*
* The crop and scale state is double-buffered state, and will be
* applied on the next wl_surface.commit.
*/
static inline void
wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height)
{
wl_proxy_marshal((struct wl_proxy *) wp_viewport,
WP_VIEWPORT_SET_SOURCE, x, y, width, height);
}
/**
* @ingroup iface_wp_viewport
*
* Set the destination size of the associated wl_surface. See
* wp_viewport for the description, and relation to the wl_buffer
* size.
*
* If width is -1 and height is -1, the destination size is unset
* instead. Any other pair of values for width and height that
* contains zero or negative values raises the bad_value protocol
* error.
*
* The crop and scale state is double-buffered state, and will be
* applied on the next wl_surface.commit.
*/
static inline void
wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height)
{
wl_proxy_marshal((struct wl_proxy *) wp_viewport,
WP_VIEWPORT_SET_DESTINATION, width, height);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,65 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2018 Simon Ser
*
* 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 (including the next
* paragraph) 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface xdg_toplevel_interface;
extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
static const struct wl_interface *xdg_decoration_unstable_v1_types[] = {
NULL,
&zxdg_toplevel_decoration_v1_interface,
&xdg_toplevel_interface,
};
static const struct wl_message zxdg_decoration_manager_v1_requests[] = {
{ "destroy", "", xdg_decoration_unstable_v1_types + 0 },
{ "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 },
};
WL_EXPORT const struct wl_interface zxdg_decoration_manager_v1_interface = {
"zxdg_decoration_manager_v1", 1,
2, zxdg_decoration_manager_v1_requests,
0, NULL,
};
static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = {
{ "destroy", "", xdg_decoration_unstable_v1_types + 0 },
{ "set_mode", "u", xdg_decoration_unstable_v1_types + 0 },
{ "unset_mode", "", xdg_decoration_unstable_v1_types + 0 },
};
static const struct wl_message zxdg_toplevel_decoration_v1_events[] = {
{ "configure", "u", xdg_decoration_unstable_v1_types + 0 },
};
WL_EXPORT const struct wl_interface zxdg_toplevel_decoration_v1_interface = {
"zxdg_toplevel_decoration_v1", 1,
3, zxdg_toplevel_decoration_v1_requests,
1, zxdg_toplevel_decoration_v1_events,
};

View file

@ -0,0 +1,376 @@
/* Generated by wayland-scanner 1.18.0 */
#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H
#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol
* @section page_ifaces_xdg_decoration_unstable_v1 Interfaces
* - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager
* - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface
* @section page_copyright_xdg_decoration_unstable_v1 Copyright
* <pre>
*
* Copyright © 2018 Simon Ser
*
* 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 (including the next
* paragraph) 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.
* </pre>
*/
struct xdg_toplevel;
struct zxdg_decoration_manager_v1;
struct zxdg_toplevel_decoration_v1;
/**
* @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1
* @section page_iface_zxdg_decoration_manager_v1_desc Description
*
* This interface allows a compositor to announce support for server-side
* decorations.
*
* A window decoration is a set of window controls as deemed appropriate by
* the party managing them, such as user interface components used to move,
* resize and change a window's state.
*
* A client can use this protocol to request being decorated by a supporting
* compositor.
*
* If compositor and client do not negotiate the use of a server-side
* decoration using this protocol, clients continue to self-decorate as they
* see fit.
*
* Warning! The protocol described in this file is experimental and
* backward incompatible changes may be made. Backward compatible changes
* may be added together with the corresponding interface version bump.
* Backward incompatible changes are done by bumping the version number in
* the protocol and interface names and resetting the interface version.
* Once the protocol is to be declared stable, the 'z' prefix and the
* version number in the protocol and interface names are removed and the
* interface version number is reset.
* @section page_iface_zxdg_decoration_manager_v1_api API
* See @ref iface_zxdg_decoration_manager_v1.
*/
/**
* @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface
*
* This interface allows a compositor to announce support for server-side
* decorations.
*
* A window decoration is a set of window controls as deemed appropriate by
* the party managing them, such as user interface components used to move,
* resize and change a window's state.
*
* A client can use this protocol to request being decorated by a supporting
* compositor.
*
* If compositor and client do not negotiate the use of a server-side
* decoration using this protocol, clients continue to self-decorate as they
* see fit.
*
* Warning! The protocol described in this file is experimental and
* backward incompatible changes may be made. Backward compatible changes
* may be added together with the corresponding interface version bump.
* Backward incompatible changes are done by bumping the version number in
* the protocol and interface names and resetting the interface version.
* Once the protocol is to be declared stable, the 'z' prefix and the
* version number in the protocol and interface names are removed and the
* interface version number is reset.
*/
extern const struct wl_interface zxdg_decoration_manager_v1_interface;
/**
* @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1
* @section page_iface_zxdg_toplevel_decoration_v1_desc Description
*
* The decoration object allows the compositor to toggle server-side window
* decorations for a toplevel surface. The client can request to switch to
* another mode.
*
* The xdg_toplevel_decoration object must be destroyed before its
* xdg_toplevel.
* @section page_iface_zxdg_toplevel_decoration_v1_api API
* See @ref iface_zxdg_toplevel_decoration_v1.
*/
/**
* @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface
*
* The decoration object allows the compositor to toggle server-side window
* decorations for a toplevel surface. The client can request to switch to
* another mode.
*
* The xdg_toplevel_decoration object must be destroyed before its
* xdg_toplevel.
*/
extern const struct wl_interface zxdg_toplevel_decoration_v1_interface;
#define ZXDG_DECORATION_MANAGER_V1_DESTROY 0
#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1
/**
* @ingroup iface_zxdg_decoration_manager_v1
*/
#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_decoration_manager_v1
*/
#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1
/** @ingroup iface_zxdg_decoration_manager_v1 */
static inline void
zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data);
}
/** @ingroup iface_zxdg_decoration_manager_v1 */
static inline void *
zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1);
}
static inline uint32_t
zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1);
}
/**
* @ingroup iface_zxdg_decoration_manager_v1
*
* Destroy the decoration manager. This doesn't destroy objects created
* with the manager.
*/
static inline void
zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1)
{
wl_proxy_marshal((struct wl_proxy *) zxdg_decoration_manager_v1,
ZXDG_DECORATION_MANAGER_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zxdg_decoration_manager_v1);
}
/**
* @ingroup iface_zxdg_decoration_manager_v1
*
* Create a new decoration object associated with the given toplevel.
*
* Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
* buffer attached or committed is a client error, and any attempts by a
* client to attach or manipulate a buffer prior to the first
* xdg_toplevel_decoration.configure event must also be treated as
* errors.
*/
static inline struct zxdg_toplevel_decoration_v1 *
zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel)
{
struct wl_proxy *id;
id = wl_proxy_marshal_constructor((struct wl_proxy *) zxdg_decoration_manager_v1,
ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, NULL, toplevel);
return (struct zxdg_toplevel_decoration_v1 *) id;
}
#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM
#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM
enum zxdg_toplevel_decoration_v1_error {
/**
* xdg_toplevel has a buffer attached before configure
*/
ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0,
/**
* xdg_toplevel already has a decoration object
*/
ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1,
/**
* xdg_toplevel destroyed before the decoration object
*/
ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2,
};
#endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */
#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM
#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
* window decoration modes
*
* These values describe window decoration modes.
*/
enum zxdg_toplevel_decoration_v1_mode {
/**
* no server-side window decoration
*/
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1,
/**
* server-side window decoration
*/
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2,
};
#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
* @struct zxdg_toplevel_decoration_v1_listener
*/
struct zxdg_toplevel_decoration_v1_listener {
/**
* suggest a surface change
*
* The configure event asks the client to change its decoration
* mode. The configured state should not be applied immediately.
* Clients must send an ack_configure in response to this event.
* See xdg_surface.configure and xdg_surface.ack_configure for
* details.
*
* A configure event can be sent at any time. The specified mode
* must be obeyed by the client.
* @param mode the decoration mode
*/
void (*configure)(void *data,
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
uint32_t mode);
};
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
*/
static inline int
zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
const struct zxdg_toplevel_decoration_v1_listener *listener, void *data)
{
return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1,
(void (**)(void)) listener, data);
}
#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0
#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1
#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
*/
#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
*/
#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
*/
#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
*/
#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1
/** @ingroup iface_zxdg_toplevel_decoration_v1 */
static inline void
zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data);
}
/** @ingroup iface_zxdg_toplevel_decoration_v1 */
static inline void *
zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
{
return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1);
}
static inline uint32_t
zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
{
return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1);
}
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
*
* Switch back to a mode without any server-side decorations at the next
* commit.
*/
static inline void
zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
{
wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
ZXDG_TOPLEVEL_DECORATION_V1_DESTROY);
wl_proxy_destroy((struct wl_proxy *) zxdg_toplevel_decoration_v1);
}
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
*
* Set the toplevel surface decoration mode. This informs the compositor
* that the client prefers the provided decoration mode.
*
* After requesting a decoration mode, the compositor will respond by
* emitting a xdg_surface.configure event. The client should then update
* its content, drawing it without decorations if the received mode is
* server-side decorations. The client must also acknowledge the configure
* when committing the new content (see xdg_surface.ack_configure).
*
* The compositor can decide not to use the client's mode and enforce a
* different mode instead.
*
* Clients whose decoration mode depend on the xdg_toplevel state may send
* a set_mode request in response to a xdg_surface.configure event and wait
* for the next xdg_surface.configure event to prevent unwanted state.
* Such clients are responsible for preventing configure loops and must
* make sure not to send multiple successive set_mode requests with the
* same decoration mode.
*/
static inline void
zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode)
{
wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, mode);
}
/**
* @ingroup iface_zxdg_toplevel_decoration_v1
*
* Unset the toplevel surface decoration mode. This informs the compositor
* that the client doesn't prefer a particular decoration mode.
*
* This request has the same semantics as set_mode.
*/
static inline void
zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1)
{
wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1,
ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,171 @@
/* Generated by wayland-scanner 1.18.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* 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 (including the next
* paragraph) 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.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_wl_xs_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_wl_xs_types + 0 },
{ "create_positioner", "n", xdg_shell_wl_xs_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_wl_xs_types + 5 },
{ "pong", "u", xdg_shell_wl_xs_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_wl_xs_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 3,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_wl_xs_types + 0 },
{ "set_size", "ii", xdg_shell_wl_xs_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_wl_xs_types + 0 },
{ "set_anchor", "u", xdg_shell_wl_xs_types + 0 },
{ "set_gravity", "u", xdg_shell_wl_xs_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_wl_xs_types + 0 },
{ "set_offset", "ii", xdg_shell_wl_xs_types + 0 },
{ "set_reactive", "3", xdg_shell_wl_xs_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_wl_xs_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_wl_xs_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 3,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_wl_xs_types + 0 },
{ "get_toplevel", "n", xdg_shell_wl_xs_types + 7 },
{ "get_popup", "n?oo", xdg_shell_wl_xs_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_wl_xs_types + 0 },
{ "ack_configure", "u", xdg_shell_wl_xs_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_wl_xs_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_surface_interface = {
"xdg_surface", 3,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_wl_xs_types + 0 },
{ "set_parent", "?o", xdg_shell_wl_xs_types + 11 },
{ "set_title", "s", xdg_shell_wl_xs_types + 0 },
{ "set_app_id", "s", xdg_shell_wl_xs_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_wl_xs_types + 12 },
{ "move", "ou", xdg_shell_wl_xs_types + 16 },
{ "resize", "ouu", xdg_shell_wl_xs_types + 18 },
{ "set_max_size", "ii", xdg_shell_wl_xs_types + 0 },
{ "set_min_size", "ii", xdg_shell_wl_xs_types + 0 },
{ "set_maximized", "", xdg_shell_wl_xs_types + 0 },
{ "unset_maximized", "", xdg_shell_wl_xs_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_wl_xs_types + 21 },
{ "unset_fullscreen", "", xdg_shell_wl_xs_types + 0 },
{ "set_minimized", "", xdg_shell_wl_xs_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_wl_xs_types + 0 },
{ "close", "", xdg_shell_wl_xs_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 3,
14, xdg_toplevel_requests,
2, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_wl_xs_types + 0 },
{ "grab", "ou", xdg_shell_wl_xs_types + 22 },
{ "reposition", "3ou", xdg_shell_wl_xs_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_wl_xs_types + 0 },
{ "popup_done", "", xdg_shell_wl_xs_types + 0 },
{ "repositioned", "3u", xdg_shell_wl_xs_types + 0 },
};
WL_EXPORT const struct wl_interface xdg_popup_interface = {
"xdg_popup", 3,
3, xdg_popup_requests,
3, xdg_popup_events,
};

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 WGL - www.glfw.org
// GLFW 3.4 WGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -75,8 +77,8 @@ static int choosePixelFormat(_GLFWwindow* window,
{
const int attrib = WGL_NUMBER_PIXEL_FORMATS_ARB;
if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc,
1, 0, 1, &attrib, &nativeCount))
if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,
1, 0, 1, &attrib, &nativeCount))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve pixel format attribute");
@ -139,10 +141,10 @@ static int choosePixelFormat(_GLFWwindow* window,
{
// Get pixel format attributes through "modern" extension
if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc,
pixelFormat, 0,
attribCount,
attribs, values))
if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,
pixelFormat, 0,
attribCount,
attribs, values))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve pixel format attributes");
@ -360,7 +362,7 @@ static void swapIntervalWGL(int interval)
}
if (_glfw.wgl.EXT_swap_control)
_glfw.wgl.SwapIntervalEXT(interval);
wglSwapIntervalEXT(interval);
}
static int extensionSupportedWGL(const char* extension)
@ -368,9 +370,9 @@ static int extensionSupportedWGL(const char* extension)
const char* extensions = NULL;
if (_glfw.wgl.GetExtensionsStringARB)
extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
extensions = wglGetExtensionsStringARB(wglGetCurrentDC());
else if (_glfw.wgl.GetExtensionsStringEXT)
extensions = _glfw.wgl.GetExtensionsStringEXT();
extensions = wglGetExtensionsStringEXT();
if (!extensions)
return GLFW_FALSE;
@ -387,8 +389,6 @@ static GLFWglproc getProcAddressWGL(const char* procname)
return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname);
}
// Destroy the OpenGL context
//
static void destroyContextWGL(_GLFWwindow* window)
{
if (window->context.wgl.handle)
@ -693,8 +693,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
setAttrib(0, 0);
window->context.wgl.handle =
_glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc,
share, attribs);
wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs);
if (!window->context.wgl.handle)
{
const DWORD error = GetLastError();

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 WGL - www.glfw.org
// GLFW 3.4 WGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
@ -76,12 +76,19 @@
#define ERROR_INVALID_PROFILE_ARB 0x2096
#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054
// WGL extension pointer typedefs
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*);
#define wglSwapIntervalEXT _glfw.wgl.SwapIntervalEXT
#define wglGetPixelFormatAttribivARB _glfw.wgl.GetPixelFormatAttribivARB
#define wglGetExtensionsStringEXT _glfw.wgl.GetExtensionsStringEXT
#define wglGetExtensionsStringARB _glfw.wgl.GetExtensionsStringARB
#define wglCreateContextAttribsARB _glfw.wgl.CreateContextAttribsARB
// opengl32.dll function pointer typedefs
typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC);
typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC);
typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR);
@ -89,8 +96,6 @@ typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void);
typedef HGLRC (WINAPI * PFN_wglGetCurrentContext)(void);
typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC);
typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC);
// opengl32.dll function pointer typedefs
#define wglCreateContext _glfw.wgl.CreateContext
#define wglDeleteContext _glfw.wgl.DeleteContext
#define wglGetProcAddress _glfw.wgl.GetProcAddress

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
// GLFW 3.4 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -523,7 +525,7 @@ BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp)
cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embedd a non-default manifest
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
}
@ -538,7 +540,7 @@ BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build)
cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
cond = VerSetConditionMask(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL);
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embedd a non-default manifest
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
}

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
// GLFW 3.4 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
// GLFW 3.4 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//
@ -25,7 +25,7 @@
//========================================================================
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickWin32 win32
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE int dummy
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE struct { int dummyLibraryJoystick; }
#define _GLFW_PLATFORM_MAPPING_NAME "Windows"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
// GLFW 3.4 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -31,6 +33,7 @@
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <wchar.h>
// Callback for EnumDisplayMonitors in createMonitor
@ -475,7 +478,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
HDC dc;
WORD values[768];
WORD values[3][256];
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
GetDeviceGammaRamp(dc, values);
@ -483,9 +486,9 @@ GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
_glfwAllocGammaArrays(ramp, 256);
memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short));
memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short));
memcpy(ramp->red, values[0], sizeof(values[0]));
memcpy(ramp->green, values[1], sizeof(values[1]));
memcpy(ramp->blue, values[2], sizeof(values[2]));
return GLFW_TRUE;
}
@ -493,7 +496,7 @@ GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
HDC dc;
WORD values[768];
WORD values[3][256];
if (ramp->size != 256)
{
@ -502,9 +505,9 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
return;
}
memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short));
memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short));
memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short));
memcpy(values[0], ramp->red, sizeof(values[0]));
memcpy(values[1], ramp->green, sizeof(values[1]));
memcpy(values[2], ramp->blue, sizeof(values[2]));
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
SetDeviceGammaRamp(dc, values);

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
// GLFW 3.4 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -212,7 +212,7 @@ typedef enum
// HACK: Define macros that some dinput.h variants don't
#ifndef DIDFT_OPTIONAL
#define DIDFT_OPTIONAL 0x80000000
#define DIDFT_OPTIONAL 0x80000000
#endif
// winmm.dll function pointer typedefs
@ -315,6 +315,7 @@ typedef struct _GLFWwindowWin32
// Whether to enable framebuffer transparency on DWM
GLFWbool transparent;
GLFWbool scaleToMonitor;
GLFWbool keymenu;
// The last received cursor position, regardless of source
int lastCursorPosX, lastCursorPosY;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
// GLFW 3.4 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
// GLFW 3.4 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Win32 - www.glfw.org
// GLFW 3.4 Win32 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -34,8 +36,6 @@
#include <windowsx.h>
#include <shellapi.h>
#define _GLFW_KEY_INVALID -2
// Returns the window style for the specified window
//
static DWORD getWindowStyle(const _GLFWwindow* window)
@ -409,7 +409,7 @@ static void updateFramebufferTransparency(const _GLFWwindow* window)
// issue. When set to black, something is making the hit test
// not resize with the window frame.
SetLayeredWindowAttributes(window->win32.handle,
RGB(0, 193, 48), 255, LWA_COLORKEY);
RGB(255, 0, 255), 255, LWA_COLORKEY);
}
DeleteObject(region);
@ -446,77 +446,6 @@ static int getKeyMods(void)
return mods;
}
// Retrieves and translates modifier keys
//
static int getAsyncKeyMods(void)
{
int mods = 0;
if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
mods |= GLFW_MOD_SHIFT;
if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
mods |= GLFW_MOD_CONTROL;
if (GetAsyncKeyState(VK_MENU) & 0x8000)
mods |= GLFW_MOD_ALT;
if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000)
mods |= GLFW_MOD_SUPER;
if (GetAsyncKeyState(VK_CAPITAL) & 1)
mods |= GLFW_MOD_CAPS_LOCK;
if (GetAsyncKeyState(VK_NUMLOCK) & 1)
mods |= GLFW_MOD_NUM_LOCK;
return mods;
}
// Translates a Windows key to the corresponding GLFW key
//
static int translateKey(WPARAM wParam, LPARAM lParam)
{
// The Ctrl keys require special handling
if (wParam == VK_CONTROL)
{
MSG next;
DWORD time;
// Right side keys have the extended key bit set
if (lParam & 0x01000000)
return GLFW_KEY_RIGHT_CONTROL;
// HACK: Alt Gr sends Left Ctrl and then Right Alt in close sequence
// We only want the Right Alt message, so if the next message is
// Right Alt we ignore this (synthetic) Left Ctrl message
time = GetMessageTime();
if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
{
if (next.message == WM_KEYDOWN ||
next.message == WM_SYSKEYDOWN ||
next.message == WM_KEYUP ||
next.message == WM_SYSKEYUP)
{
if (next.wParam == VK_MENU &&
(next.lParam & 0x01000000) &&
next.time == time)
{
// Next message is Right Alt down so discard this
return _GLFW_KEY_INVALID;
}
}
}
return GLFW_KEY_LEFT_CONTROL;
}
if (wParam == VK_PROCESSKEY)
{
// IME notifies that keys have been filtered by setting the virtual
// key-code to VK_PROCESSKEY
return _GLFW_KEY_INVALID;
}
return _glfw.win32.keycodes[HIWORD(lParam) & 0x1FF];
}
static void fitToMonitor(_GLFWwindow* window)
{
MONITORINFO mi = { sizeof(mi) };
@ -629,12 +558,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
// clicking a caption button
if (HIWORD(lParam) == WM_LBUTTONDOWN)
{
if (LOWORD(lParam) == HTCLOSE ||
LOWORD(lParam) == HTMINBUTTON ||
LOWORD(lParam) == HTMAXBUTTON)
{
if (LOWORD(lParam) != HTCLIENT)
window->win32.frameAction = GLFW_TRUE;
}
}
break;
@ -701,7 +626,12 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
// User trying to access application menu using ALT?
case SC_KEYMENU:
return 0;
{
if (!window->win32.keymenu)
return 0;
break;
}
}
break;
}
@ -733,6 +663,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
}
_glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain);
if (uMsg == WM_SYSCHAR && window->win32.keymenu)
break;
return 0;
}
@ -741,13 +675,64 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_KEYUP:
case WM_SYSKEYUP:
{
const int key = translateKey(wParam, lParam);
const int scancode = (lParam >> 16) & 0x1ff;
const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS;
int key, scancode;
const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS;
const int mods = getKeyMods();
if (key == _GLFW_KEY_INVALID)
scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
if (!scancode)
{
// NOTE: Some synthetic key messages have a scancode of zero
// HACK: Map the virtual key back to a usable scancode
scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC);
}
key = _glfw.win32.keycodes[scancode];
// The Ctrl keys require special handling
if (wParam == VK_CONTROL)
{
if (HIWORD(lParam) & KF_EXTENDED)
{
// Right side keys have the extended key bit set
key = GLFW_KEY_RIGHT_CONTROL;
}
else
{
// NOTE: Alt Gr sends Left Ctrl followed by Right Alt
// HACK: We only want one event for Alt Gr, so if we detect
// this sequence we discard this Left Ctrl message now
// and later report Right Alt normally
MSG next;
const DWORD time = GetMessageTime();
if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
{
if (next.message == WM_KEYDOWN ||
next.message == WM_SYSKEYDOWN ||
next.message == WM_KEYUP ||
next.message == WM_SYSKEYUP)
{
if (next.wParam == VK_MENU &&
(HIWORD(next.lParam) & KF_EXTENDED) &&
next.time == time)
{
// Next message is Right Alt down so discard this
break;
}
}
}
// This is a regular Left Ctrl message
key = GLFW_KEY_LEFT_CONTROL;
}
}
else if (wParam == VK_PROCESSKEY)
{
// IME notifies that keys have been filtered by setting the
// virtual key-code to VK_PROCESSKEY
break;
}
if (action == GLFW_RELEASE && wParam == VK_SHIFT)
{
@ -830,7 +815,19 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
// Disabled cursor motion input is provided by WM_INPUT
if (!window->win32.cursorTracked)
{
TRACKMOUSEEVENT tme;
ZeroMemory(&tme, sizeof(tme));
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = window->win32.handle;
TrackMouseEvent(&tme);
window->win32.cursorTracked = GLFW_TRUE;
_glfwInputCursorEnter(window, GLFW_TRUE);
}
if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
const int dx = x - window->win32.lastCursorPosX;
@ -851,19 +848,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
window->win32.lastCursorPosX = x;
window->win32.lastCursorPosY = y;
if (!window->win32.cursorTracked)
{
TRACKMOUSEEVENT tme;
ZeroMemory(&tme, sizeof(tme));
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = window->win32.handle;
TrackMouseEvent(&tme);
window->win32.cursorTracked = GLFW_TRUE;
_glfwInputCursorEnter(window, GLFW_TRUE);
}
return 0;
}
@ -942,6 +926,9 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_ENTERSIZEMOVE:
case WM_ENTERMENULOOP:
{
if (window->win32.frameAction)
break;
// HACK: Enable the cursor while the user is moving or
// resizing the window or using the window menu
if (window->cursorMode == GLFW_CURSOR_DISABLED)
@ -953,6 +940,9 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_EXITSIZEMOVE:
case WM_EXITMENULOOP:
{
if (window->win32.frameAction)
break;
// HACK: Disable the cursor once the user is done moving or
// resizing the window or using the menu
if (window->cursorMode == GLFW_CURSOR_DISABLED)
@ -1225,6 +1215,7 @@ static int createNativeWindow(_GLFWwindow* window,
xpos = CW_USEDEFAULT;
ypos = CW_USEDEFAULT;
window->win32.maximized = wndconfig->maximized;
if (wndconfig->maximized)
style |= WS_MAXIMIZE;
@ -1271,13 +1262,15 @@ static int createNativeWindow(_GLFWwindow* window,
}
window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
window->win32.keymenu = wndconfig->win32.keymenu;
// Adjust window size to account for DPI scaling of the window frame and
// optionally DPI scaling of the content area
// This cannot be done until we know what monitor it was placed on
// Adjust window rect to account for DPI scaling of the window frame and
// (if enabled) DPI scaling of the content area
// This cannot be done until we know what monitor the window was placed on
if (!window->monitor)
{
RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
WINDOWPLACEMENT wp = { sizeof(wp) };
if (wndconfig->scaleToMonitor)
{
@ -1298,10 +1291,11 @@ static int createNativeWindow(_GLFWwindow* window,
else
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
SetWindowPos(window->win32.handle, NULL,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
// Only update the restored window rect as the window may be maximized
GetWindowPlacement(window->win32.handle, &wp);
wp.rcNormalPosition = rect;
wp.showCmd = SW_HIDE;
SetWindowPlacement(window->win32.handle, &wp);
}
DragAcceptFiles(window->win32.handle, TRUE);
@ -1722,7 +1716,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_glfwInputWindowMonitor(window, monitor);
if (monitor)
if (window->monitor)
{
MONITORINFO mi = { sizeof(mi) };
UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS;
@ -1918,30 +1912,40 @@ void _glfwPlatformPollEvents(void)
}
}
// HACK: Release modifier keys that the system did not emit KEYUP for
// NOTE: Shift keys on Windows tend to "stick" when both are pressed as
// no key up message is generated by the first key release
// NOTE: Windows key is not reported as released by the Win+V hotkey
// Other Win hotkeys are handled implicitly by _glfwInputWindowFocus
// because they change the input focus
// NOTE: The other half of this is in the WM_*KEY* handler in windowProc
handle = GetActiveWindow();
if (handle)
{
// NOTE: Shift keys on Windows tend to "stick" when both are pressed as
// no key up message is generated by the first key release
// The other half of this is in the handling of WM_KEYUP
// HACK: Query actual key state and synthesize release events as needed
window = GetPropW(handle, L"GLFW");
if (window)
{
const GLFWbool lshift = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1;
const GLFWbool rshift = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1;
int i;
const int keys[4][2] =
{
{ VK_LSHIFT, GLFW_KEY_LEFT_SHIFT },
{ VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT },
{ VK_LWIN, GLFW_KEY_LEFT_SUPER },
{ VK_RWIN, GLFW_KEY_RIGHT_SUPER }
};
if (!lshift && window->keys[GLFW_KEY_LEFT_SHIFT] == GLFW_PRESS)
for (i = 0; i < 4; i++)
{
const int mods = getAsyncKeyMods();
const int scancode = _glfw.win32.scancodes[GLFW_KEY_LEFT_SHIFT];
_glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods);
}
else if (!rshift && window->keys[GLFW_KEY_RIGHT_SHIFT] == GLFW_PRESS)
{
const int mods = getAsyncKeyMods();
const int scancode = _glfw.win32.scancodes[GLFW_KEY_RIGHT_SHIFT];
_glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods);
const int vk = keys[i][0];
const int key = keys[i][1];
const int scancode = _glfw.win32.scancodes[key];
if ((GetKeyState(vk) & 0x8000))
continue;
if (window->keys[key] != GLFW_PRESS)
continue;
_glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods());
}
}
}
@ -2023,6 +2027,13 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
const char* _glfwPlatformGetScancodeName(int scancode)
{
if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) ||
_glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");
return NULL;
}
return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]];
}
@ -2052,14 +2063,25 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
id = OCR_IBEAM;
else if (shape == GLFW_CROSSHAIR_CURSOR)
id = OCR_CROSS;
else if (shape == GLFW_HAND_CURSOR)
else if (shape == GLFW_POINTING_HAND_CURSOR)
id = OCR_HAND;
else if (shape == GLFW_HRESIZE_CURSOR)
else if (shape == GLFW_RESIZE_EW_CURSOR)
id = OCR_SIZEWE;
else if (shape == GLFW_VRESIZE_CURSOR)
else if (shape == GLFW_RESIZE_NS_CURSOR)
id = OCR_SIZENS;
else if (shape == GLFW_RESIZE_NWSE_CURSOR)
id = OCR_SIZENWSE;
else if (shape == GLFW_RESIZE_NESW_CURSOR)
id = OCR_SIZENESW;
else if (shape == GLFW_RESIZE_ALL_CURSOR)
id = OCR_SIZEALL;
else if (shape == GLFW_NOT_ALLOWED_CURSOR)
id = OCR_NO;
else
{
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Unknown standard cursor");
return GLFW_FALSE;
}
cursor->win32.handle = LoadImageW(NULL,
MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0,

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -25,6 +25,8 @@
// distribution.
//
//========================================================================
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
#include "internal.h"
@ -361,6 +363,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_COCOA_RETINA_FRAMEBUFFER:
_glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_WIN32_KEYBOARD_MENU:
_glfw.hints.window.win32.keymenu = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_COCOA_GRAPHICS_SWITCHING:
_glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
return;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@ -23,6 +23,10 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
//#define _POSIX_C_SOURCE 199309L
#include "internal.h"
@ -36,6 +40,7 @@
#include <sys/mman.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <time.h>
#include <wayland-client.h>
@ -123,6 +128,7 @@ static void pointerHandleLeave(void* data,
_glfw.wl.serial = serial;
_glfw.wl.pointerFocus = NULL;
_glfwInputCursorEnter(window, GLFW_FALSE);
_glfw.wl.cursorPreviousName = NULL;
}
static void setCursor(_GLFWwindow* window, const char* name)
@ -167,6 +173,7 @@ static void setCursor(_GLFWwindow* window, const char* name)
wl_surface_damage(surface, 0, 0,
image->width, image->height);
wl_surface_commit(surface);
_glfw.wl.cursorPreviousName = name;
}
static void pointerHandleMotion(void* data,
@ -176,48 +183,47 @@ static void pointerHandleMotion(void* data,
wl_fixed_t sy)
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
const char* cursorName;
const char* cursorName = NULL;
double x, y;
if (!window)
return;
if (window->cursorMode == GLFW_CURSOR_DISABLED)
return;
else
{
window->wl.cursorPosX = wl_fixed_to_double(sx);
window->wl.cursorPosY = wl_fixed_to_double(sy);
}
x = wl_fixed_to_double(sx);
y = wl_fixed_to_double(sy);
switch (window->wl.decorations.focus)
{
case mainWindow:
_glfwInputCursorPos(window,
wl_fixed_to_double(sx),
wl_fixed_to_double(sy));
window->wl.cursorPosX = x;
window->wl.cursorPosY = y;
_glfwInputCursorPos(window, x, y);
_glfw.wl.cursorPreviousName = NULL;
return;
case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
if (y < _GLFW_DECORATION_WIDTH)
cursorName = "n-resize";
else
cursorName = "left_ptr";
break;
case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
if (y < _GLFW_DECORATION_WIDTH)
cursorName = "nw-resize";
else
cursorName = "w-resize";
break;
case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
if (y < _GLFW_DECORATION_WIDTH)
cursorName = "ne-resize";
else
cursorName = "e-resize";
break;
case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
if (x < _GLFW_DECORATION_WIDTH)
cursorName = "sw-resize";
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
else if (x > window->wl.width + _GLFW_DECORATION_WIDTH)
cursorName = "se-resize";
else
cursorName = "s-resize";
@ -225,7 +231,8 @@ static void pointerHandleMotion(void* data,
default:
assert(0);
}
setCursor(window, cursorName);
if (_glfw.wl.cursorPreviousName != cursorName)
setCursor(window, cursorName);
}
static void pointerHandleButton(void* data,
@ -237,9 +244,7 @@ static void pointerHandleButton(void* data,
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
int glfwButton;
// Both xdg-shell and wl_shell use the same values.
uint32_t edges = WL_SHELL_SURFACE_RESIZE_NONE;
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
if (!window)
return;
@ -251,46 +256,39 @@ static void pointerHandleButton(void* data,
break;
case topDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP;
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else
{
if (window->wl.xdg.toplevel)
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
else
wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, serial);
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
}
break;
case leftDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
else
edges = WL_SHELL_SURFACE_RESIZE_LEFT;
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
break;
case rightDecoration:
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
else
edges = WL_SHELL_SURFACE_RESIZE_RIGHT;
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
break;
case bottomDecoration:
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
else
edges = WL_SHELL_SURFACE_RESIZE_BOTTOM;
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
break;
default:
assert(0);
}
if (edges != WL_SHELL_SURFACE_RESIZE_NONE)
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
{
if (window->wl.xdg.toplevel)
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
serial, edges);
else
wl_shell_surface_resize(window->wl.shellSurface, _glfw.wl.seat,
serial, edges);
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
serial, edges);
}
}
else if (button == BTN_RIGHT)
@ -805,11 +803,6 @@ static void registryHandleGlobal(void* data,
_glfw.wl.shm =
wl_registry_bind(registry, name, &wl_shm_interface, 1);
}
else if (strcmp(interface, "wl_shell") == 0)
{
_glfw.wl.shell =
wl_registry_bind(registry, name, &wl_shell_interface, 1);
}
else if (strcmp(interface, "wl_output") == 0)
{
_glfwAddOutputWayland(name, version);
@ -1164,6 +1157,13 @@ int _glfwPlatformInit(void)
if (_glfw.wl.seatVersion >= 4)
_glfw.wl.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
if (!_glfw.wl.wmBase)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to find xdg-shell in your compositor");
return GLFW_FALSE;
}
if (_glfw.wl.pointer && _glfw.wl.shm)
{
cursorTheme = getenv("XCURSOR_THEME");
@ -1257,8 +1257,6 @@ void _glfwPlatformTerminate(void)
wl_compositor_destroy(_glfw.wl.compositor);
if (_glfw.wl.shm)
wl_shm_destroy(_glfw.wl.shm);
if (_glfw.wl.shell)
wl_shell_destroy(_glfw.wl.shell);
if (_glfw.wl.viewporter)
wp_viewporter_destroy(_glfw.wl.viewporter);
if (_glfw.wl.decorationManager)

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@ -23,6 +23,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -198,7 +200,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Gamma ramp access it not available");
"Wayland: Gamma ramp access is not available");
return GLFW_FALSE;
}

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@ -75,8 +75,8 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl
#define _GLFW_PLATFORM_CONTEXT_STATE
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
#define _GLFW_PLATFORM_CONTEXT_STATE struct { int dummyContext; }
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE struct { int dummyLibraryContext; }
struct wl_cursor_image {
uint32_t width;
@ -180,7 +180,6 @@ typedef struct _GLFWwindowWayland
GLFWbool transparent;
struct wl_surface* surface;
struct wl_egl_window* native;
struct wl_shell_surface* shellSurface;
struct wl_callback* callback;
struct {
@ -227,7 +226,6 @@ typedef struct _GLFWlibraryWayland
struct wl_registry* registry;
struct wl_compositor* compositor;
struct wl_subcompositor* subcompositor;
struct wl_shell* shell;
struct wl_shm* shm;
struct wl_seat* seat;
struct wl_pointer* pointer;
@ -249,6 +247,7 @@ typedef struct _GLFWlibraryWayland
struct wl_cursor_theme* cursorTheme;
struct wl_cursor_theme* cursorThemeHiDPI;
struct wl_surface* cursorSurface;
const char* cursorPreviousName;
int cursorTimerfd;
uint32_t serial;
@ -332,7 +331,7 @@ typedef struct _GLFWlibraryWayland
typedef struct _GLFWmonitorWayland
{
struct wl_output* output;
int name;
uint32_t name;
int currentMode;
int x;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@ -23,6 +23,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#define _GNU_SOURCE
@ -39,72 +41,6 @@
#include <poll.h>
static void shellSurfaceHandlePing(void* data,
struct wl_shell_surface* shellSurface,
uint32_t serial)
{
wl_shell_surface_pong(shellSurface, serial);
}
static void shellSurfaceHandleConfigure(void* data,
struct wl_shell_surface* shellSurface,
uint32_t edges,
int32_t width,
int32_t height)
{
_GLFWwindow* window = data;
float aspectRatio;
float targetRatio;
if (!window->monitor)
{
if (_glfw.wl.viewporter && window->decorated)
{
width -= _GLFW_DECORATION_HORIZONTAL;
height -= _GLFW_DECORATION_VERTICAL;
}
if (width < 1)
width = 1;
if (height < 1)
height = 1;
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
{
aspectRatio = (float)width / (float)height;
targetRatio = (float)window->numer / (float)window->denom;
if (aspectRatio < targetRatio)
height = width / targetRatio;
else if (aspectRatio > targetRatio)
width = height * targetRatio;
}
if (window->minwidth != GLFW_DONT_CARE && width < window->minwidth)
width = window->minwidth;
else if (window->maxwidth != GLFW_DONT_CARE && width > window->maxwidth)
width = window->maxwidth;
if (window->minheight != GLFW_DONT_CARE && height < window->minheight)
height = window->minheight;
else if (window->maxheight != GLFW_DONT_CARE && height > window->maxheight)
height = window->maxheight;
}
_glfwInputWindowSize(window, width, height);
_glfwPlatformSetWindowSize(window, width, height);
_glfwInputWindowDamage(window);
}
static void shellSurfaceHandlePopupDone(void* data,
struct wl_shell_surface* shellSurface)
{
}
static const struct wl_shell_surface_listener shellSurfaceListener = {
shellSurfaceHandlePing,
shellSurfaceHandleConfigure,
shellSurfaceHandlePopupDone
};
static int createTmpfileCloexec(char* tmpname)
{
int fd;
@ -132,7 +68,7 @@ static int createTmpfileCloexec(char* tmpname)
* SCM_RIGHTS methods.
*
* posix_fallocate() is used to guarantee that disk space is available
* for the file at the given size. If disk space is insufficent, errno
* for the file at the given size. If disk space is insufficient, errno
* is set to ENOSPC. If posix_fallocate() is not supported, program may
* receive SIGBUS on accessing mmap()'ed file contents instead.
*/
@ -529,66 +465,11 @@ static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor,
window->wl.xdg.toplevel,
monitor->wl.output);
}
else if (window->wl.shellSurface)
{
wl_shell_surface_set_fullscreen(
window->wl.shellSurface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
refreshRate * 1000, // Convert Hz to mHz.
monitor->wl.output);
}
setIdleInhibitor(window, GLFW_TRUE);
if (!window->wl.decorations.serverSide)
destroyDecorations(window);
}
static GLFWbool createShellSurface(_GLFWwindow* window)
{
if (!_glfw.wl.shell)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: wl_shell protocol not available");
return GLFW_FALSE;
}
window->wl.shellSurface = wl_shell_get_shell_surface(_glfw.wl.shell,
window->wl.surface);
if (!window->wl.shellSurface)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Shell surface creation failed");
return GLFW_FALSE;
}
wl_shell_surface_add_listener(window->wl.shellSurface,
&shellSurfaceListener,
window);
if (window->wl.title)
wl_shell_surface_set_title(window->wl.shellSurface, window->wl.title);
if (window->monitor)
{
setFullscreen(window, window->monitor, 0);
}
else if (window->wl.maximized)
{
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
setIdleInhibitor(window, GLFW_FALSE);
createDecorations(window);
}
else
{
wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE);
createDecorations(window);
}
wl_surface_commit(window->wl.surface);
return GLFW_TRUE;
}
static void xdgToplevelHandleConfigure(void* data,
struct xdg_toplevel* toplevel,
int32_t width,
@ -889,28 +770,6 @@ static void handleEvents(int timeout)
}
}
// Translates a GLFW standard cursor to a theme cursor name
//
static char *translateCursorShape(int shape)
{
switch (shape)
{
case GLFW_ARROW_CURSOR:
return "left_ptr";
case GLFW_IBEAM_CURSOR:
return "xterm";
case GLFW_CROSSHAIR_CURSOR:
return "crosshair";
case GLFW_HAND_CURSOR:
return "grabbing";
case GLFW_HRESIZE_CURSOR:
return "sb_h_double_arrow";
case GLFW_VRESIZE_CURSOR:
return "sb_v_double_arrow";
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
@ -949,16 +808,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (wndconfig->visible)
{
if (_glfw.wl.wmBase)
{
if (!createXdgSurface(window))
return GLFW_FALSE;
}
else
{
if (!createShellSurface(window))
return GLFW_FALSE;
}
if (!createXdgSurface(window))
return GLFW_FALSE;
window->wl.visible = GLFW_TRUE;
}
@ -966,7 +817,6 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{
window->wl.xdg.surface = NULL;
window->wl.xdg.toplevel = NULL;
window->wl.shellSurface = NULL;
window->wl.visible = GLFW_FALSE;
}
@ -1008,9 +858,6 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
if (window->wl.native)
wl_egl_window_destroy(window->wl.native);
if (window->wl.shellSurface)
wl_shell_surface_destroy(window->wl.shellSurface);
if (window->wl.xdg.toplevel)
xdg_toplevel_destroy(window->wl.xdg.toplevel);
@ -1031,8 +878,6 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
window->wl.title = _glfw_strdup(title);
if (window->wl.xdg.toplevel)
xdg_toplevel_set_title(window->wl.xdg.toplevel, title);
else if (window->wl.shellSurface)
wl_shell_surface_set_title(window->wl.shellSurface, title);
}
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
@ -1078,23 +923,15 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
{
if (_glfw.wl.wmBase)
if (window->wl.xdg.toplevel)
{
if (window->wl.xdg.toplevel)
{
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
minwidth = minheight = 0;
if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
maxwidth = maxheight = 0;
xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);
xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);
wl_surface_commit(window->wl.surface);
}
}
else
{
// TODO: find out how to trigger a resize.
// The actual limits are checked in the wl_shell_surface::configure handler.
if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
minwidth = minheight = 0;
if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
maxwidth = maxheight = 0;
xdg_toplevel_set_min_size(window->wl.xdg.toplevel, minwidth, minheight);
xdg_toplevel_set_max_size(window->wl.xdg.toplevel, maxwidth, maxheight);
wl_surface_commit(window->wl.surface);
}
}
@ -1102,7 +939,7 @@ void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window,
int numer, int denom)
{
// TODO: find out how to trigger a resize.
// The actual limits are checked in the wl_shell_surface::configure handler.
// The actual limits are checked in the xdg_toplevel::configure handler.
}
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window,
@ -1141,16 +978,8 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
{
if (_glfw.wl.wmBase)
{
if (window->wl.xdg.toplevel)
xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Iconify window not supported on wl_shell");
}
if (window->wl.xdg.toplevel)
xdg_toplevel_set_minimized(window->wl.xdg.toplevel);
}
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
@ -1162,12 +991,7 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
if (window->wl.maximized)
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
// There is no way to unset minimized, or even to know if we are
// minimized, so there is nothing to do here.
}
else if (window->wl.shellSurface)
{
if (window->monitor || window->wl.maximized)
wl_shell_surface_set_toplevel(window->wl.shellSurface);
// minimized, so there is nothing to do in this case.
}
_glfwInputWindowMonitor(window, NULL);
window->wl.maximized = GLFW_FALSE;
@ -1179,11 +1003,6 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
}
else if (window->wl.shellSurface)
{
// Let the compositor select the best output.
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
}
window->wl.maximized = GLFW_TRUE;
}
@ -1191,10 +1010,7 @@ void _glfwPlatformShowWindow(_GLFWwindow* window)
{
if (!window->wl.visible)
{
if (_glfw.wl.wmBase)
createXdgSurface(window);
else if (!window->wl.shellSurface)
createShellSurface(window);
createXdgSurface(window);
window->wl.visible = GLFW_TRUE;
}
}
@ -1208,11 +1024,6 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
window->wl.xdg.toplevel = NULL;
window->wl.xdg.surface = NULL;
}
else if (window->wl.shellSurface)
{
wl_shell_surface_destroy(window->wl.shellSurface);
window->wl.shellSurface = NULL;
}
window->wl.visible = GLFW_FALSE;
}
@ -1243,8 +1054,6 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
{
if (window->wl.xdg.toplevel)
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
else if (window->wl.shellSurface)
wl_shell_surface_set_toplevel(window->wl.shellSurface);
setIdleInhibitor(window, GLFW_FALSE);
if (!_glfw.wl.decorationManager)
createDecorations(window);
@ -1259,8 +1068,8 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window)
int _glfwPlatformWindowIconified(_GLFWwindow* window)
{
// wl_shell doesn't have any iconified concept, and xdg-shell doesnt give
// any way to request whether a surface is iconified.
// xdg-shell doesnt give any way to request whether a surface is
// iconified.
return GLFW_FALSE;
}
@ -1402,26 +1211,79 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{
struct wl_cursor* standardCursor;
const char* name = NULL;
standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
translateCursorShape(shape));
if (!standardCursor)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Standard cursor \"%s\" not found",
translateCursorShape(shape));
return GLFW_FALSE;
}
// Try the XDG names first
if (shape == GLFW_ARROW_CURSOR)
name = "default";
else if (shape == GLFW_IBEAM_CURSOR)
name = "text";
else if (shape == GLFW_CROSSHAIR_CURSOR)
name = "crosshair";
else if (shape == GLFW_POINTING_HAND_CURSOR)
name = "pointer";
else if (shape == GLFW_RESIZE_EW_CURSOR)
name = "ew-resize";
else if (shape == GLFW_RESIZE_NS_CURSOR)
name = "ns-resize";
else if (shape == GLFW_RESIZE_NWSE_CURSOR)
name = "nwse-resize";
else if (shape == GLFW_RESIZE_NESW_CURSOR)
name = "nesw-resize";
else if (shape == GLFW_RESIZE_ALL_CURSOR)
name = "all-scroll";
else if (shape == GLFW_NOT_ALLOWED_CURSOR)
name = "not-allowed";
cursor->wl.cursor = standardCursor;
cursor->wl.currentImage = 0;
cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
if (_glfw.wl.cursorThemeHiDPI)
{
standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,
translateCursorShape(shape));
cursor->wl.cursorHiDPI = standardCursor;
cursor->wl.cursorHiDPI =
wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name);
}
if (!cursor->wl.cursor)
{
// Fall back to the core X11 names
if (shape == GLFW_ARROW_CURSOR)
name = "left_ptr";
else if (shape == GLFW_IBEAM_CURSOR)
name = "xterm";
else if (shape == GLFW_CROSSHAIR_CURSOR)
name = "crosshair";
else if (shape == GLFW_POINTING_HAND_CURSOR)
name = "hand2";
else if (shape == GLFW_RESIZE_EW_CURSOR)
name = "sb_h_double_arrow";
else if (shape == GLFW_RESIZE_NS_CURSOR)
name = "sb_v_double_arrow";
else if (shape == GLFW_RESIZE_ALL_CURSOR)
name = "fleur";
else
{
_glfwInputError(GLFW_CURSOR_UNAVAILABLE,
"Wayland: Standard cursor shape unavailable");
return GLFW_FALSE;
}
cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
if (!cursor->wl.cursor)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create standard cursor \"%s\"",
name);
return GLFW_FALSE;
}
if (_glfw.wl.cursorThemeHiDPI)
{
if (!cursor->wl.cursorHiDPI)
{
cursor->wl.cursorHiDPI =
wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name);
}
}
}
return GLFW_TRUE;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -34,6 +36,7 @@
#include <limits.h>
#include <stdio.h>
#include <locale.h>
#include <unistd.h>
// Translate an X11 key code to a GLFW key code.
@ -52,7 +55,7 @@ static int translateKeyCode(int scancode)
// Note: This way we always force "NumLock = ON", which is intentional
// since the returned key code should correspond to a physical
// location.
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 1);
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 1);
switch (keySym)
{
case XK_KP_0: return GLFW_KEY_KP_0;
@ -74,7 +77,7 @@ static int translateKeyCode(int scancode)
// Now try primary keysym for function keys (non-printable keys)
// These should not depend on the current keyboard layout
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0);
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0);
}
else
{
@ -329,14 +332,13 @@ static void createKeyTables(void)
//
static GLFWbool hasUsableInputMethodStyle(void)
{
unsigned int i;
GLFWbool found = GLFW_FALSE;
XIMStyles* styles = NULL;
if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
return GLFW_FALSE;
for (i = 0; i < styles->count_styles; i++)
for (unsigned int i = 0; i < styles->count_styles; i++)
{
if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing))
{
@ -355,10 +357,9 @@ static Atom getSupportedAtom(Atom* supportedAtoms,
unsigned long atomCount,
const char* atomName)
{
unsigned long i;
const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
for (i = 0; i < atomCount; i++)
for (unsigned int i = 0; i < atomCount; i++)
{
if (supportedAtoms[i] == atom)
return atom;
@ -371,18 +372,11 @@ static Atom getSupportedAtom(Atom* supportedAtoms,
//
static void detectEWMH(void)
{
// First we read the _NET_SUPPORTING_WM_CHECK property on the root window
Window* windowFromRoot = NULL;
Window* windowFromChild = NULL;
// First we need a couple of atoms
const Atom supportingWmCheck =
XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
const Atom wmSupported =
XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
// Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
if (!_glfwGetWindowPropertyX11(_glfw.x11.root,
supportingWmCheck,
_glfw.x11.NET_SUPPORTING_WM_CHECK,
XA_WINDOW,
(unsigned char**) &windowFromRoot))
{
@ -391,10 +385,12 @@ static void detectEWMH(void)
_glfwGrabErrorHandlerX11();
// It should be the ID of a child window (of the root)
// Then we look for the same property on the child window
// If it exists, it should be the XID of a top-level window
// Then we look for the same property on that window
Window* windowFromChild = NULL;
if (!_glfwGetWindowPropertyX11(*windowFromRoot,
supportingWmCheck,
_glfw.x11.NET_SUPPORTING_WM_CHECK,
XA_WINDOW,
(unsigned char**) &windowFromChild))
{
@ -404,7 +400,8 @@ static void detectEWMH(void)
_glfwReleaseErrorHandlerX11();
// It should be the ID of that same child window
// If the property exists, it should contain the XID of the window
if (*windowFromRoot != *windowFromChild)
{
XFree(windowFromRoot);
@ -415,19 +412,20 @@ static void detectEWMH(void)
XFree(windowFromRoot);
XFree(windowFromChild);
// We are now fairly sure that an EWMH-compliant window manager is running
// We are now fairly sure that an EWMH-compliant WM is currently running
// We can now start querying the WM about what features it supports by
// looking in the _NET_SUPPORTED property on the root window
// It should contain a list of supported EWMH protocol and state atoms
Atom* supportedAtoms;
unsigned long atomCount;
// Now we need to check the _NET_SUPPORTED property of the root window
// It should be a list of supported WM protocol and state atoms
atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root,
wmSupported,
XA_ATOM,
(unsigned char**) &supportedAtoms);
Atom* supportedAtoms = NULL;
const unsigned long atomCount =
_glfwGetWindowPropertyX11(_glfw.x11.root,
_glfw.x11.NET_SUPPORTED,
XA_ATOM,
(unsigned char**) &supportedAtoms);
// See which of the atoms we support that are supported by the WM
_glfw.x11.NET_WM_STATE =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
_glfw.x11.NET_WM_STATE_ABOVE =
@ -618,6 +616,12 @@ static GLFWbool initExtensions(void)
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
_glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
_glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme)
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetTheme");
_glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize)
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize");
_glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage)
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage");
}
#if defined(__CYGWIN__)
@ -662,6 +666,14 @@ static GLFWbool initExtensions(void)
if (supported)
_glfw.x11.xkb.detectable = GLFW_TRUE;
}
_glfw.x11.xkb.group = 0;
XkbStateRec state;
if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success)
{
XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask);
_glfw.x11.xkb.group = (unsigned int)state.group;
}
}
#if defined(__CYGWIN__)
@ -707,9 +719,6 @@ static GLFWbool initExtensions(void)
// the keyboard mapping.
createKeyTables();
// Detect whether an EWMH-conformant window manager is running
detectEWMH();
// String format atoms
_glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
_glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
@ -753,6 +762,10 @@ static GLFWbool initExtensions(void)
XInternAtom(_glfw.x11.display, "WM_STATE", False);
_glfw.x11.WM_DELETE_WINDOW =
XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
_glfw.x11.NET_SUPPORTED =
XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
_glfw.x11.NET_SUPPORTING_WM_CHECK =
XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
_glfw.x11.NET_WM_ICON =
XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
_glfw.x11.NET_WM_PING =
@ -777,6 +790,9 @@ static GLFWbool initExtensions(void)
_glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False);
}
// Detect whether an EWMH-conformant window manager is running
detectEWMH();
return GLFW_TRUE;
}
@ -784,13 +800,10 @@ static GLFWbool initExtensions(void)
//
static void getSystemContentScale(float* xscale, float* yscale)
{
// NOTE: Fall back to the display-wide DPI instead of RandR monitor DPI if
// Xft.dpi retrieval below fails as we don't currently have an exact
// policy for which monitor a window is considered to "be on"
float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) *
25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) *
25.4f / DisplayHeightMM(_glfw.x11.display, _glfw.x11.screen);
// Start by assuming the default X11 DPI
// NOTE: Some desktop environments (KDE) may remove the Xft.dpi field when it
// would be set to 96, so assume that is the case if we cannot find it
float xdpi = 96.f, ydpi = 96.f;
// NOTE: Basing the scale on Xft.dpi where available should provide the most
// consistent user experience (matches Qt, Gtk, etc), although not

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -54,9 +56,7 @@ static int calculateRefreshRate(const XRRModeInfo* mi)
//
static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
{
int i;
for (i = 0; i < sr->nmode; i++)
for (int i = 0; i < sr->nmode; i++)
{
if (sr->modes[i].id == id)
return sr->modes + i;
@ -102,7 +102,7 @@ void _glfwPollMonitorsX11(void)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
int i, j, disconnectedCount, screenCount = 0;
int disconnectedCount, screenCount = 0;
_GLFWmonitor** disconnected = NULL;
XineramaScreenInfo* screens = NULL;
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
@ -122,14 +122,11 @@ void _glfwPollMonitorsX11(void)
_glfw.monitorCount * sizeof(_GLFWmonitor*));
}
for (i = 0; i < sr->noutput; i++)
for (int i = 0; i < sr->noutput; i++)
{
int type, widthMM, heightMM;
XRROutputInfo* oi;
XRRCrtcInfo* ci;
_GLFWmonitor* monitor;
int j, type, widthMM, heightMM;
oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, sr->outputs[i]);
if (oi->connection != RR_Connected || oi->crtc == None)
{
XRRFreeOutputInfo(oi);
@ -152,7 +149,7 @@ void _glfwPollMonitorsX11(void)
continue;
}
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
{
widthMM = oi->mm_height;
@ -164,7 +161,17 @@ void _glfwPollMonitorsX11(void)
heightMM = oi->mm_height;
}
monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
if (widthMM <= 0 || heightMM <= 0)
{
// HACK: If RandR does not provide a physical size, assume the
// X11 default 96 DPI and calcuate from the CRTC viewport
// NOTE: These members are affected by rotation, unlike the mode
// info and output info members
widthMM = (int) (ci->width * 25.4f / 96.f);
heightMM = (int) (ci->height * 25.4f / 96.f);
}
_GLFWmonitor* monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
monitor->x11.output = sr->outputs[i];
monitor->x11.crtc = oi->crtc;
@ -196,7 +203,7 @@ void _glfwPollMonitorsX11(void)
if (screens)
XFree(screens);
for (i = 0; i < disconnectedCount; i++)
for (int i = 0; i < disconnectedCount; i++)
{
if (disconnected[i])
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
@ -221,24 +228,20 @@ void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
XRROutputInfo* oi;
GLFWvidmode current;
const GLFWvidmode* best;
RRMode native = None;
int i;
best = _glfwChooseVideoMode(monitor, desired);
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
_glfwPlatformGetVideoMode(monitor, &current);
if (_glfwCompareVideoModes(&current, best) == 0)
return;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
for (i = 0; i < oi->nmode; i++)
for (int i = 0; i < oi->nmode; i++)
{
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
if (!modeIsGood(mi))
@ -279,14 +282,12 @@ void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
if (monitor->x11.oldMode == None)
return;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRRSetCrtcConfig(_glfw.x11.display,
sr, monitor->x11.crtc,
@ -317,18 +318,20 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
if (ci)
{
if (xpos)
*xpos = ci->x;
if (ypos)
*ypos = ci->y;
if (xpos)
*xpos = ci->x;
if (ypos)
*ypos = ci->y;
XRRFreeCrtcInfo(ci);
}
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
}
}
@ -348,11 +351,9 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
areaX = ci->x;
areaY = ci->y;
@ -444,24 +445,21 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
int i, j;
XRRScreenResources* sr;
XRRCrtcInfo* ci;
XRROutputInfo* oi;
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
result = calloc(oi->nmode, sizeof(GLFWvidmode));
for (i = 0; i < oi->nmode; i++)
for (int i = 0; i < oi->nmode; i++)
{
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
if (!modeIsGood(mi))
continue;
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
int j;
for (j = 0; j < *count; j++)
{
@ -495,15 +493,19 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
{
XRRScreenResources* sr;
XRRCrtcInfo* ci;
XRRScreenResources* sr =
XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
if (ci)
{
const XRRModeInfo* mi = getModeInfo(sr, ci->mode);
if (mi) // mi can be NULL if the monitor has been disconnected
*mode = vidmodeFromModeInfo(mi, ci);
*mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci);
XRRFreeCrtcInfo(ci);
}
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
}
else

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -85,9 +85,15 @@ typedef int (* PFN_XRRUpdateConfiguration)(XEvent*);
typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int);
typedef void (* PFN_XcursorImageDestroy)(XcursorImage*);
typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*);
typedef char* (* PFN_XcursorGetTheme)(Display*);
typedef int (* PFN_XcursorGetDefaultSize)(Display*);
typedef XcursorImage* (* PFN_XcursorLibraryLoadImage)(const char*,const char*,int);
#define XcursorImageCreate _glfw.x11.xcursor.ImageCreate
#define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy
#define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor
#define XcursorGetTheme _glfw.x11.xcursor.GetTheme
#define XcursorGetDefaultSize _glfw.x11.xcursor.GetDefaultSize
#define XcursorLibraryLoadImage _glfw.x11.xcursor.LibraryLoadImage
typedef Bool (* PFN_XineramaIsActive)(Display*);
typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*);
@ -180,6 +186,7 @@ typedef struct _GLFWwindowX11
{
Colormap colormap;
Window handle;
Window parent;
XIC ic;
GLFWbool overrideRedirect;
@ -228,7 +235,7 @@ typedef struct _GLFWlibraryX11
// Clipboard string (while the selection is owned)
char* clipboardString;
// Key name string
char keyName[5];
char keynames[GLFW_KEY_LAST + 1][5];
// X11 keycode to GLFW key LUT
short int keycodes[256];
// GLFW key to X11 keycode LUT
@ -239,6 +246,8 @@ typedef struct _GLFWlibraryX11
_GLFWwindow* disabledCursorWindow;
// Window manager atoms
Atom NET_SUPPORTED;
Atom NET_SUPPORTING_WM_CHECK;
Atom WM_PROTOCOLS;
Atom WM_STATE;
Atom WM_DELETE_WINDOW;
@ -321,13 +330,14 @@ typedef struct _GLFWlibraryX11
} randr;
struct {
GLFWbool available;
GLFWbool detectable;
int majorOpcode;
int eventBase;
int errorBase;
int major;
int minor;
GLFWbool available;
GLFWbool detectable;
int majorOpcode;
int eventBase;
int errorBase;
int major;
int minor;
unsigned int group;
} xkb;
struct {
@ -349,6 +359,9 @@ typedef struct _GLFWlibraryX11
PFN_XcursorImageCreate ImageCreate;
PFN_XcursorImageDestroy ImageDestroy;
PFN_XcursorImageLoadCursor ImageLoadCursor;
PFN_XcursorGetTheme GetTheme;
PFN_XcursorGetDefaultSize GetDefaultSize;
PFN_XcursorLibraryLoadImage LibraryLoadImage;
} xcursor;
struct {

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"
@ -48,6 +50,10 @@
#define Button6 6
#define Button7 7
// Motif WM hints flags
#define MWM_HINTS_DECORATIONS 2
#define MWM_DECOR_ALL 1
#define _GLFW_XDND_VERSION 5
@ -213,10 +219,7 @@ static int translateKey(int scancode)
static void sendEventToWM(_GLFWwindow* window, Atom type,
long a, long b, long c, long d, long e)
{
XEvent event;
memset(&event, 0, sizeof(event));
event.type = ClientMessage;
XEvent event = { ClientMessage };
event.xclient.window = window->x11.handle;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = type;
@ -610,46 +613,41 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
window->x11.transparent = _glfwIsVisualTransparentX11(visual);
// Create the actual window
XSetWindowAttributes wa = { 0 };
wa.colormap = window->x11.colormap;
wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
ExposureMask | FocusChangeMask | VisibilityChangeMask |
EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
_glfwGrabErrorHandlerX11();
window->x11.parent = _glfw.x11.root;
window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root,
0, 0, // Position
width, height,
0, // Border width
depth, // Color depth
InputOutput,
visual,
CWBorderPixel | CWColormap | CWEventMask,
&wa);
_glfwReleaseErrorHandlerX11();
if (!window->x11.handle)
{
XSetWindowAttributes wa;
const unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask;
wa.colormap = window->x11.colormap;
wa.border_pixel = 0;
wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
ExposureMask | FocusChangeMask | VisibilityChangeMask |
EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
_glfwGrabErrorHandlerX11();
window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root,
0, 0,
width, height,
0, // Border width
depth, // Color depth
InputOutput,
visual,
wamask,
&wa);
_glfwReleaseErrorHandlerX11();
if (!window->x11.handle)
{
_glfwInputErrorX11(GLFW_PLATFORM_ERROR,
"X11: Failed to create window");
return GLFW_FALSE;
}
XSaveContext(_glfw.x11.display,
window->x11.handle,
_glfw.x11.context,
(XPointer) window);
_glfwInputErrorX11(GLFW_PLATFORM_ERROR,
"X11: Failed to create window");
return GLFW_FALSE;
}
XSaveContext(_glfw.x11.display,
window->x11.handle,
_glfw.x11.context,
(XPointer) window);
if (!wndconfig->decorated)
_glfwPlatformSetWindowDecorated(window, GLFW_FALSE);
@ -679,7 +677,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
{
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char*) &states, count);
PropModeReplace, (unsigned char*) states, count);
}
}
@ -784,6 +782,13 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
NULL);
}
if (window->x11.ic)
{
unsigned long filter = 0;
if (XGetICValues(window->x11.ic, XNFilterEvents, &filter, NULL) == NULL)
XSelectInput(_glfw.x11.display, window->x11.handle, wa.event_mask | filter);
}
_glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos);
_glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height);
@ -944,11 +949,8 @@ static void handleSelectionRequest(XEvent* event)
{
const XSelectionRequestEvent* request = &event->xselectionrequest;
XEvent reply;
memset(&reply, 0, sizeof(reply));
XEvent reply = { SelectionNotify };
reply.xselection.property = writeTargetToProperty(request);
reply.xselection.type = SelectionNotify;
reply.xselection.display = request->display;
reply.xselection.requestor = request->requestor;
reply.xselection.selection = request->selection;
@ -960,7 +962,6 @@ static void handleSelectionRequest(XEvent* event)
static const char* getSelectionString(Atom selection)
{
size_t i;
char** selectionString = NULL;
const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING };
const size_t targetCount = sizeof(targets) / sizeof(targets[0]);
@ -981,7 +982,7 @@ static const char* getSelectionString(Atom selection)
free(*selectionString);
*selectionString = NULL;
for (i = 0; i < targetCount; i++)
for (size_t i = 0; i < targetCount; i++)
{
char* data;
Atom actualType;
@ -1165,7 +1166,6 @@ static void releaseMonitor(_GLFWwindow* window)
//
static void processEvent(XEvent *event)
{
_GLFWwindow* window = NULL;
int keycode = 0;
Bool filtered = False;
@ -1186,6 +1186,18 @@ static void processEvent(XEvent *event)
}
}
if (_glfw.x11.xkb.available)
{
if (event->type == _glfw.x11.xkb.eventBase + XkbEventCode)
{
if (((XkbEvent*) event)->any.xkb_type == XkbStateNotify &&
(((XkbEvent*) event)->state.changed & XkbGroupStateMask))
{
_glfw.x11.xkb.group = ((XkbEvent*) event)->state.group;
}
}
}
if (event->type == GenericEvent)
{
if (_glfw.x11.xi.available)
@ -1235,6 +1247,7 @@ static void processEvent(XEvent *event)
return;
}
_GLFWwindow* window = NULL;
if (XFindContext(_glfw.x11.display,
event->xany.window,
_glfw.x11.context,
@ -1246,6 +1259,12 @@ static void processEvent(XEvent *event)
switch (event->type)
{
case ReparentNotify:
{
window->x11.parent = event->xreparent.parent;
return;
}
case KeyPress:
{
const int key = translateKey(keycode);
@ -1530,18 +1549,28 @@ static void processEvent(XEvent *event)
window->x11.height = event->xconfigure.height;
}
if (event->xconfigure.x != window->x11.xpos ||
event->xconfigure.y != window->x11.ypos)
{
if (window->x11.overrideRedirect || event->xany.send_event)
{
_glfwInputWindowPos(window,
event->xconfigure.x,
event->xconfigure.y);
int xpos = event->xconfigure.x;
int ypos = event->xconfigure.y;
window->x11.xpos = event->xconfigure.x;
window->x11.ypos = event->xconfigure.y;
}
// NOTE: ConfigureNotify events from the server are in local
// coordinates, so if we are reparented we need to translate
// the position into root (screen) coordinates
if (!event->xany.send_event && window->x11.parent != _glfw.x11.root)
{
Window dummy;
XTranslateCoordinates(_glfw.x11.display,
window->x11.parent,
_glfw.x11.root,
xpos, ypos,
&xpos, &ypos,
&dummy);
}
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
{
_glfwInputWindowPos(window, xpos, ypos);
window->x11.xpos = xpos;
window->x11.ypos = ypos;
}
return;
@ -1646,10 +1675,7 @@ static void processEvent(XEvent *event)
}
else if (_glfw.x11.xdnd.version >= 2)
{
XEvent reply;
memset(&reply, 0, sizeof(reply));
reply.type = ClientMessage;
XEvent reply = { ClientMessage };
reply.xclient.window = _glfw.x11.xdnd.source;
reply.xclient.message_type = _glfw.x11.XdndFinished;
reply.xclient.format = 32;
@ -1682,10 +1708,7 @@ static void processEvent(XEvent *event)
_glfwInputCursorPos(window, xpos, ypos);
XEvent reply;
memset(&reply, 0, sizeof(reply));
reply.type = ClientMessage;
XEvent reply = { ClientMessage };
reply.xclient.window = _glfw.x11.xdnd.source;
reply.xclient.message_type = _glfw.x11.XdndStatus;
reply.xclient.format = 32;
@ -1738,10 +1761,7 @@ static void processEvent(XEvent *event)
if (_glfw.x11.xdnd.version >= 2)
{
XEvent reply;
memset(&reply, 0, sizeof(reply));
reply.type = ClientMessage;
XEvent reply = { ClientMessage };
reply.xclient.window = _glfw.x11.xdnd.source;
reply.xclient.message_type = _glfw.x11.XdndFinished;
reply.xclient.format = 32;
@ -1760,9 +1780,6 @@ static void processEvent(XEvent *event)
case FocusIn:
{
if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window);
if (event->xfocus.mode == NotifyGrab ||
event->xfocus.mode == NotifyUngrab)
{
@ -1771,6 +1788,9 @@ static void processEvent(XEvent *event)
return;
}
if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window);
if (window->x11.ic)
XSetICFocus(window->x11.ic);
@ -1780,9 +1800,6 @@ static void processEvent(XEvent *event)
case FocusOut:
{
if (window->cursorMode == GLFW_CURSOR_DISABLED)
enableCursor(window);
if (event->xfocus.mode == NotifyGrab ||
event->xfocus.mode == NotifyUngrab)
{
@ -1791,6 +1808,9 @@ static void processEvent(XEvent *event)
return;
}
if (window->cursorMode == GLFW_CURSOR_DISABLED)
enableCursor(window);
if (window->x11.ic)
XUnsetICFocus(window->x11.ic);
@ -2338,18 +2358,67 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
{
if (_glfw.x11.NET_WM_STATE &&
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
if (!_glfw.x11.NET_WM_STATE ||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
{
return;
}
if (_glfwPlatformWindowVisible(window))
{
sendEventToWM(window,
_glfw.x11.NET_WM_STATE,
_NET_WM_STATE_ADD,
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
1, 0);
XFlush(_glfw.x11.display);
_glfw.x11.NET_WM_STATE,
_NET_WM_STATE_ADD,
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ,
1, 0);
}
else
{
Atom* states = NULL;
unsigned long count =
_glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE,
XA_ATOM,
(unsigned char**) &states);
// NOTE: We don't check for failure as this property may not exist yet
// and that's fine (and we'll create it implicitly with append)
Atom missing[2] =
{
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT,
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ
};
unsigned long missingCount = 2;
for (unsigned long i = 0; i < count; i++)
{
for (unsigned long j = 0; j < missingCount; j++)
{
if (states[i] == missing[j])
{
missing[j] = missing[missingCount - 1];
missingCount--;
}
}
}
if (states)
XFree(states);
if (!missingCount)
return;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) missing,
missingCount);
}
XFlush(_glfw.x11.display);
}
void _glfwPlatformShowWindow(_GLFWwindow* window)
@ -2369,6 +2438,9 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
{
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION)
return;
sendEventToWM(window,
_glfw.x11.NET_WM_STATE,
_NET_WM_STATE_ADD,
@ -2380,7 +2452,7 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
{
if (_glfw.x11.NET_ACTIVE_WINDOW)
sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0);
else
else if (_glfwPlatformWindowVisible(window))
{
XRaiseWindow(_glfw.x11.display, window->x11.handle);
XSetInputFocus(_glfw.x11.display, window->x11.handle,
@ -2538,33 +2610,24 @@ void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
{
if (enabled)
struct
{
XDeleteProperty(_glfw.x11.display,
window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS);
}
else
{
struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
} hints;
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
} hints = {0};
hints.flags = 2; // Set decorations
hints.decorations = 0; // No decorations
hints.flags = MWM_HINTS_DECORATIONS;
hints.decorations = enabled ? MWM_DECOR_ALL : 0;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS,
_glfw.x11.MOTIF_WM_HINTS, 32,
PropModeReplace,
(unsigned char*) &hints,
sizeof(hints) / sizeof(long));
}
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS,
_glfw.x11.MOTIF_WM_HINTS, 32,
PropModeReplace,
(unsigned char*) &hints,
sizeof(hints) / sizeof(long));
}
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
@ -2574,7 +2637,7 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
if (_glfwPlatformWindowVisible(window))
{
const Atom action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
const long action = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
sendEventToWM(window,
_glfw.x11.NET_WM_STATE,
action,
@ -2583,15 +2646,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
}
else
{
Atom* states;
Atom* states = NULL;
unsigned long i, count;
count = _glfwGetWindowPropertyX11(window->x11.handle,
_glfw.x11.NET_WM_STATE,
XA_ATOM,
(unsigned char**) &states);
if (!states)
return;
// NOTE: We don't check for failure as this property may not exist yet
// and that's fine (and we'll create it implicitly with append)
if (enabled)
{
@ -2601,32 +2665,36 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
break;
}
if (i == count)
{
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
1);
}
if (i < count)
return;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeAppend,
(unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE,
1);
}
else
else if (states)
{
for (i = 0; i < count; i++)
{
if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE)
{
states[i] = states[count - 1];
count--;
}
break;
}
if (i == count)
return;
states[i] = states[count - 1];
count--;
XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char*) &states, count);
PropModeReplace, (unsigned char*) states, count);
}
XFree(states);
if (states)
XFree(states);
}
XFlush(_glfw.x11.display);
@ -2737,10 +2805,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
void _glfwPlatformPostEmptyEvent(void)
{
XEvent event;
memset(&event, 0, sizeof(event));
event.type = ClientMessage;
XEvent event = { ClientMessage };
event.xclient.window = _glfw.x11.helperWindowHandle;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = _glfw.x11.NULL_;
@ -2797,7 +2862,16 @@ const char* _glfwPlatformGetScancodeName(int scancode)
if (!_glfw.x11.xkb.available)
return NULL;
const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0);
if (scancode < 0 || scancode > 0xff ||
_glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");
return NULL;
}
const int key = _glfw.x11.keycodes[scancode];
const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display,
scancode, _glfw.x11.xkb.group, 0);
if (keysym == NoSymbol)
return NULL;
@ -2805,12 +2879,12 @@ const char* _glfwPlatformGetScancodeName(int scancode)
if (ch == -1)
return NULL;
const size_t count = encodeUTF8(_glfw.x11.keyName, (unsigned int) ch);
const size_t count = encodeUTF8(_glfw.x11.keynames[key], (unsigned int) ch);
if (count == 0)
return NULL;
_glfw.x11.keyName[count] = '\0';
return _glfw.x11.keyName;
_glfw.x11.keynames[key][count] = '\0';
return _glfw.x11.keynames[key];
}
int _glfwPlatformGetKeyScancode(int key)
@ -2831,29 +2905,76 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{
int native = 0;
if (_glfw.x11.xcursor.handle)
{
char* theme = XcursorGetTheme(_glfw.x11.display);
if (theme)
{
const int size = XcursorGetDefaultSize(_glfw.x11.display);
const char* name = NULL;
if (shape == GLFW_ARROW_CURSOR)
native = XC_left_ptr;
else if (shape == GLFW_IBEAM_CURSOR)
native = XC_xterm;
else if (shape == GLFW_CROSSHAIR_CURSOR)
native = XC_crosshair;
else if (shape == GLFW_HAND_CURSOR)
native = XC_hand2;
else if (shape == GLFW_HRESIZE_CURSOR)
native = XC_sb_h_double_arrow;
else if (shape == GLFW_VRESIZE_CURSOR)
native = XC_sb_v_double_arrow;
else
return GLFW_FALSE;
if (shape == GLFW_ARROW_CURSOR)
name = "default";
else if (shape == GLFW_IBEAM_CURSOR)
name = "text";
else if (shape == GLFW_CROSSHAIR_CURSOR)
name = "crosshair";
else if (shape == GLFW_POINTING_HAND_CURSOR)
name = "pointer";
else if (shape == GLFW_RESIZE_EW_CURSOR)
name = "ew-resize";
else if (shape == GLFW_RESIZE_NS_CURSOR)
name = "ns-resize";
else if (shape == GLFW_RESIZE_NWSE_CURSOR)
name = "nwse-resize";
else if (shape == GLFW_RESIZE_NESW_CURSOR)
name = "nesw-resize";
else if (shape == GLFW_RESIZE_ALL_CURSOR)
name = "all-scroll";
else if (shape == GLFW_NOT_ALLOWED_CURSOR)
name = "not-allowed";
XcursorImage* image = XcursorLibraryLoadImage(name, theme, size);
if (image)
{
cursor->x11.handle = XcursorImageLoadCursor(_glfw.x11.display, image);
XcursorImageDestroy(image);
}
}
}
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
if (!cursor->x11.handle)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to create standard cursor");
return GLFW_FALSE;
unsigned int native = 0;
if (shape == GLFW_ARROW_CURSOR)
native = XC_left_ptr;
else if (shape == GLFW_IBEAM_CURSOR)
native = XC_xterm;
else if (shape == GLFW_CROSSHAIR_CURSOR)
native = XC_crosshair;
else if (shape == GLFW_POINTING_HAND_CURSOR)
native = XC_hand2;
else if (shape == GLFW_RESIZE_EW_CURSOR)
native = XC_sb_h_double_arrow;
else if (shape == GLFW_RESIZE_NS_CURSOR)
native = XC_sb_v_double_arrow;
else if (shape == GLFW_RESIZE_ALL_CURSOR)
native = XC_fleur;
else
{
_glfwInputError(GLFW_CURSOR_UNAVAILABLE,
"X11: Standard cursor shape unavailable");
return GLFW_FALSE;
}
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
if (!cursor->x11.handle)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to create standard cursor");
return GLFW_FALSE;
}
}
return GLFW_TRUE;

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@ -24,6 +24,8 @@
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include "internal.h"

View file

@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
// GLFW 3.4 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//

File diff suppressed because it is too large Load diff

View file

@ -1154,7 +1154,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
while (cmd) {
char *arg = strtok(0, " ");
if (!arg) {
puts("lsystem error: unexpected end of program.");
//puts("lsystem error: unexpected end of program.");
break;
}
if (!strcmp(cmd, "rule")) {
@ -1208,6 +1208,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
// For testing purposes, dump out the parsed program.
#ifdef TEST_PARSE
/*
for (int i = 0; i < nrules; i++) {
par_shapes__rule rule = rules[i];
printf("rule %s.%d\n", rule.name, rule.weight);
@ -1216,6 +1217,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
printf("\t%s %s\n", cmd.cmd, cmd.arg);
}
}
*/
#endif
// Instantiate the aggregated shape and the template shapes.
@ -1256,8 +1258,7 @@ par_shapes_mesh* par_shapes_create_lsystem(char const* text, int slices,
par_shapes__command* cmd = rule->commands + (frame->pc++);
#ifdef DUMP_TRACE
printf("%5s %5s %5s:%d %03d\n", cmd->cmd, cmd->arg, rule->name,
frame->pc - 1, stackptr);
//printf("%5s %5s %5s:%d %03d\n", cmd->cmd, cmd->arg, rule->name, frame->pc - 1, stackptr);
#endif
float value;
@ -1619,7 +1620,7 @@ static void par_shapes__weld_points(par_shapes_mesh* mesh, int gridsize,
PAR_SHAPES_T binvalue = *(bins + binindex);
if (binvalue > 0) {
if (nbins == 8) {
printf("Epsilon value is too large.\n");
//printf("Epsilon value is too large.\n");
break;
}
nearby[nbins++] = binindex;

View file

@ -81,7 +81,7 @@
#ifndef RGIF_H
#define RGIF_H
#include <stdio.h> // Required for: FILE
#include <stdio.h> // Required for: FILE
//#define RGIF_STATIC
#ifdef RGIF_STATIC
@ -117,16 +117,6 @@ RGIFDEF bool GifEnd();
#include <stdio.h> // Required for: FILE, fopen(), fclose()
#include <string.h> // Required for: memcpy()
// Define these macros to hook into a custom memory allocator.
// RGIF_TEMP_MALLOC and RGIF_TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs
// and any temp memory allocated by a function will be freed before it exits.
#if !defined(RGIF_TEMP_MALLOC)
#include <stdlib.h>
#define RGIF_TEMP_MALLOC malloc
#define RGIF_TEMP_FREE free
#endif
// Check if custom malloc/free functions defined, if not, using standard ones
// RGIF_MALLOC and RGIF_FREE are used only by GifBegin and GifEnd respectively,
// to allocate a buffer the size of the image, which is used to find changed pixels for delta-encoding.
@ -185,7 +175,7 @@ typedef struct GifLzwNode {
//----------------------------------------------------------------------------------
const int gifTransparentIndex = 0; // Transparent color index
static FILE *gifFile;
static FILE *gifFile = NULL;
unsigned char *gifFrame;
//----------------------------------------------------------------------------------
@ -201,9 +191,10 @@ static void GifMakePalette(const unsigned char *lastFrame, const unsigned char *
static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal);
static void GifThresholdImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal);
static void GifWriteBit(GifBitStatus *stat, unsigned int bit);
static void GifWriteChunk(FILE *f, GifBitStatus *stat);
static void GifWritePalette(FILE *f, const GifPalette *pPal);
static void GifWriteCode(FILE *f, GifBitStatus *stat, unsigned int code, unsigned int length);
static void GifWritePalette(const GifPalette *pPal, FILE *f);
static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int delay, GifPalette *pPal);
//----------------------------------------------------------------------------------
@ -591,7 +582,7 @@ static void GifMakePalette(const unsigned char *lastFrame, const unsigned char *
// SplitPalette is destructive (it sorts the pixels by color) so
// we must create a copy of the image for it to destroy
int imageSize = width*height*4*sizeof(unsigned char);
unsigned char *destroyableImage = (unsigned char*)RGIF_TEMP_MALLOC(imageSize);
unsigned char *destroyableImage = (unsigned char*)RGIF_MALLOC(imageSize);
memcpy(destroyableImage, nextFrame, imageSize);
int numPixels = width*height;
@ -604,7 +595,7 @@ static void GifMakePalette(const unsigned char *lastFrame, const unsigned char *
GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal);
RGIF_TEMP_FREE(destroyableImage);
RGIF_FREE(destroyableImage);
// add the bottom node for the transparency index
pPal->treeSplit[1 << (bitDepth-1)] = 0;
@ -621,7 +612,7 @@ static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *
// quantPixels initially holds color*256 for all pixels
// The extra 8 bits of precision allow for sub-single-color error values
// to be propagated
int *quantPixels = (int*)RGIF_TEMP_MALLOC(sizeof(int)*numPixels*4);
int *quantPixels = (int*)RGIF_MALLOC(sizeof(int)*numPixels*4);
for (int ii=0; ii<numPixels*4; ++ii)
{
@ -719,7 +710,7 @@ static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *
outFrame[ii] = quantPixels[ii];
}
RGIF_TEMP_FREE(quantPixels);
RGIF_FREE(quantPixels);
}
// Picks palette colors for the image using simple thresholding, no dithering
@ -805,7 +796,7 @@ static void GifWriteCode(FILE *f, GifBitStatus *stat, unsigned int code, unsigne
}
// write a 256-color (8-bit) image palette to the file
static void GifWritePalette(const GifPalette *pPal, FILE *f)
static void GifWritePalette(FILE *f, const GifPalette *pPal)
{
fputc(0, f); // first color: transparency
fputc(0, f);
@ -852,14 +843,14 @@ static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, u
//fputc(0x80, f); // no local color table, but transparency
fputc(0x80 + pPal->bitDepth-1, f); // local color table present, 2 ^ bitDepth entries
GifWritePalette(pPal, f);
GifWritePalette(f, pPal);
const int minCodeSize = pPal->bitDepth;
const unsigned int clearCode = 1 << pPal->bitDepth;
fputc(minCodeSize, f); // min code size 8 bits
GifLzwNode *codetree = (GifLzwNode *)RGIF_TEMP_MALLOC(sizeof(GifLzwNode)*4096);
GifLzwNode *codetree = (GifLzwNode *)RGIF_MALLOC(sizeof(GifLzwNode)*4096);
memset(codetree, 0, sizeof(GifLzwNode)*4096);
int curCode = -1;
@ -933,7 +924,7 @@ static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, u
fputc(0, f); // image block terminator
RGIF_TEMP_FREE(codetree);
RGIF_FREE(codetree);
}
#endif // RGIF_IMPLEMENTATION

View file

@ -11,6 +11,7 @@ rm -f "$GLGLFW_PATH"/wayland-pointer-constraints-unstable-v1-client-protocol.{h,
rm -f "$GLGLFW_PATH"/wayland-relative-pointer-unstable-v1-client-protocol.{h,c}
rm -f "$GLGLFW_PATH"/wayland-idle-inhibit-unstable-v1-client-protocol.{h,c}
rm -f "$GLGLFW_PATH"/wayland-xdg-shell-client-protocol.{h,c}
rm -f "$GLGLFW_PATH"/wayland-xdg-decoration-client-protocol.{h,c}
rm -f "$GLGLFW_PATH"/wayland-viewporter-client-protocol.{h,c}
wayland-scanner code ./unstable/pointer-constraints/pointer-constraints-unstable-v1.xml "$GLGLFW_PATH"/wayland-pointer-constraints-unstable-v1-client-protocol.c
@ -25,6 +26,9 @@ wayland-scanner client-header ./unstable/idle-inhibit/idle-inhibit-unstable-v1.x
wayland-scanner code ./stable/xdg-shell/xdg-shell.xml "$GLGLFW_PATH"/wayland-xdg-shell-client-protocol.c
wayland-scanner client-header ./stable/xdg-shell/xdg-shell.xml "$GLGLFW_PATH"/wayland-xdg-shell-client-protocol.h
wayland-scanner code ./unstable/xdg-decoration/xdg-decoration-unstable-v1.xml "$GLGLFW_PATH"/wayland-xdg-decoration-client-protocol.c
wayland-scanner client-header ./unstable/xdg-decoration/xdg-decoration-unstable-v1.xml "$GLGLFW_PATH"/wayland-xdg-decoration-client-protocol.h
wayland-scanner code ./stable/viewporter/viewporter.xml "$GLGLFW_PATH"/wayland-viewporter-client-protocol.c
wayland-scanner client-header ./stable/viewporter/viewporter.xml "$GLGLFW_PATH"/wayland-viewporter-client-protocol.h

View file

@ -1,4 +1,4 @@
/* stb_image - v2.23 - public domain image loader - http://nothings.org/stb
/* stb_image - v2.25 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
Do this:
@ -48,10 +48,12 @@ LICENSE
RECENT REVISION HISTORY:
2.25 (2020-02-02) fix warnings
2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
2.23 (2019-08-11) fix clang static analysis warning
2.22 (2019-03-04) gif fixes, fix warnings
2.21 (2019-02-25) fix typo in comment
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
@ -105,7 +107,8 @@ RECENT REVISION HISTORY:
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus
Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo
Christian Floisand Kevin Schmidt JR Smith github:darealshinji
Blazej Dariusz Roszkowski github:Michaelangel007
Brad Weinberger Matvey Cherevko github:Michaelangel007
Blazej Dariusz Roszkowski Alexander Veselov
*/
#ifndef STBI_INCLUDE_STB_IMAGE_H
@ -434,7 +437,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f);
// get a VERY brief reason for failure
// NOT THREADSAFE
// on most compilers (and ALL modern mainstream compilers) this is threadsafe
STBIDEF const char *stbi_failure_reason (void);
// free the loaded image -- this is just free()
@ -467,6 +470,11 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
// flip the image vertically, so the first pixel in the output array is the bottom left
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
// as above, but only applies to images loaded on the thread that calls the function
// this function is only available if your compiler supports thread-local variables;
// calling it will fail to link if your compiler doesn't
STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
// ZLIB client - used by PNG, available for other purposes
STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
@ -563,6 +571,17 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#define stbi_inline __forceinline
#endif
#ifndef STBI_NO_THREAD_LOCALS
#if defined(__cplusplus) && __cplusplus >= 201103L
#define STBI_THREAD_LOCAL thread_local
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define STBI_THREAD_LOCAL _Thread_local
#elif defined(__GNUC__)
#define STBI_THREAD_LOCAL __thread
#elif defined(_MSC_VER)
#define STBI_THREAD_LOCAL __declspec(thread)
#endif
#endif
#ifdef _MSC_VER
typedef unsigned short stbi__uint16;
@ -873,19 +892,24 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int
static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
#endif
// this is not threadsafe
static const char *stbi__g_failure_reason;
static
#ifdef STBI_THREAD_LOCAL
STBI_THREAD_LOCAL
#endif
const char *stbi__g_failure_reason;
STBIDEF const char *stbi_failure_reason(void)
{
return stbi__g_failure_reason;
}
#ifndef STBI_NO_FAILURE_STRINGS
static int stbi__err(const char *str)
{
stbi__g_failure_reason = str;
return 0;
}
#endif
static void *stbi__malloc(size_t size)
{
@ -924,11 +948,13 @@ static int stbi__mul2sizes_valid(int a, int b)
return a <= INT_MAX/b;
}
#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
static int stbi__mad2sizes_valid(int a, int b, int add)
{
return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
}
#endif
// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
static int stbi__mad3sizes_valid(int a, int b, int c, int add)
@ -946,12 +972,14 @@ static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
}
#endif
#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
// mallocs with size overflow checking
static void *stbi__malloc_mad2(int a, int b, int add)
{
if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
return stbi__malloc(a*b + add);
}
#endif
static void *stbi__malloc_mad3(int a, int b, int c, int add)
{
@ -995,13 +1023,29 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
#endif
static int stbi__vertically_flip_on_load = 0;
static int stbi__vertically_flip_on_load_global = 0;
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
{
stbi__vertically_flip_on_load = flag_true_if_should_flip;
stbi__vertically_flip_on_load_global = flag_true_if_should_flip;
}
#ifndef STBI_THREAD_LOCAL
#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global
#else
static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;
STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)
{
stbi__vertically_flip_on_load_local = flag_true_if_should_flip;
stbi__vertically_flip_on_load_set = 1;
}
#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \
? stbi__vertically_flip_on_load_local \
: stbi__vertically_flip_on_load_global)
#endif // STBI_THREAD_LOCAL
static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
{
memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
@ -1023,6 +1067,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
#endif
#ifndef STBI_NO_PSD
if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
#else
STBI_NOTUSED(bpc);
#endif
#ifndef STBI_NO_PIC
if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
@ -1111,8 +1157,8 @@ static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int byt
stbi_uc *bytes = (stbi_uc *)image;
for (slice = 0; slice < z; ++slice) {
stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
bytes += slice_size;
stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
bytes += slice_size;
}
}
#endif
@ -1198,7 +1244,7 @@ static FILE *stbi__fopen(char const *filename, char const *mode)
wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
return 0;
@ -1300,15 +1346,15 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u
STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
{
unsigned char *result;
stbi__context s;
stbi__start_mem(&s,buffer,len);
stbi__context s;
stbi__start_mem(&s,buffer,len);
result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
if (stbi__vertically_flip_on_load) {
stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
}
return result;
return result;
}
#endif
@ -1477,6 +1523,9 @@ stbi_inline static stbi_uc stbi__get8(stbi__context *s)
return 0;
}
#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
// nothing
#else
stbi_inline static int stbi__at_eof(stbi__context *s)
{
if (s->io.read) {
@ -1488,7 +1537,11 @@ stbi_inline static int stbi__at_eof(stbi__context *s)
return s->img_buffer >= s->img_buffer_end;
}
#endif
#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)
// nothing
#else
static void stbi__skip(stbi__context *s, int n)
{
if (n < 0) {
@ -1505,7 +1558,11 @@ static void stbi__skip(stbi__context *s, int n)
}
s->img_buffer += n;
}
#endif
#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)
// nothing
#else
static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
{
if (s->io.read) {
@ -1529,18 +1586,27 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
} else
return 0;
}
#endif
#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
// nothing
#else
static int stbi__get16be(stbi__context *s)
{
int z = stbi__get8(s);
return (z << 8) + stbi__get8(s);
}
#endif
#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
// nothing
#else
static stbi__uint32 stbi__get32be(stbi__context *s)
{
stbi__uint32 z = stbi__get16be(s);
return (z << 16) + stbi__get16be(s);
}
#endif
#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
// nothing
@ -1562,7 +1628,9 @@ static stbi__uint32 stbi__get32le(stbi__context *s)
#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings
#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
// nothing
#else
//////////////////////////////////////////////////////////////////////////////
//
// generic converter from built-in img_n to req_comp
@ -1578,7 +1646,11 @@ static stbi_uc stbi__compute_y(int r, int g, int b)
{
return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8);
}
#endif
#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
// nothing
#else
static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
int i,j;
@ -1622,12 +1694,20 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
STBI_FREE(data);
return good;
}
#endif
#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
// nothing
#else
static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
{
return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
}
#endif
#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
// nothing
#else
static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
int i,j;
@ -1671,6 +1751,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r
STBI_FREE(data);
return good;
}
#endif
#ifndef STBI_NO_LINEAR
static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
@ -4942,6 +5023,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
++s->img_n;
}
STBI_FREE(z->expanded); z->expanded = NULL;
// end of PNG chunk, read and skip CRC
stbi__get32be(s);
return 1;
}
@ -5111,7 +5194,7 @@ static int stbi__shiftsigned(unsigned int v, int shift, int bits)
v <<= -shift;
else
v >>= shift;
STBI_ASSERT(v >= 0 && v < 256);
STBI_ASSERT(v < 256);
v >>= (8-bits);
STBI_ASSERT(bits >= 0 && bits <= 8);
return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
@ -5121,6 +5204,7 @@ typedef struct
{
int bpp, offset, hsz;
unsigned int mr,mg,mb,ma, all_a;
int extra_read;
} stbi__bmp_data;
static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
@ -5133,6 +5217,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
info->offset = stbi__get32le(s);
info->hsz = hsz = stbi__get32le(s);
info->mr = info->mg = info->mb = info->ma = 0;
info->extra_read = 14;
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
if (hsz == 12) {
@ -5176,6 +5261,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
info->mr = stbi__get32le(s);
info->mg = stbi__get32le(s);
info->mb = stbi__get32le(s);
info->extra_read += 12;
// not documented, but generated by photoshop and handled by mspaint
if (info->mr == info->mg && info->mg == info->mb) {
// ?!?!?
@ -5232,10 +5318,13 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
if (info.hsz == 12) {
if (info.bpp < 24)
psize = (info.offset - 14 - 24) / 3;
psize = (info.offset - info.extra_read - 24) / 3;
} else {
if (info.bpp < 16)
psize = (info.offset - 14 - info.hsz) >> 2;
psize = (info.offset - info.extra_read - info.hsz) >> 2;
}
if (psize == 0) {
STBI_ASSERT(info.offset == (s->img_buffer - s->buffer_start));
}
if (info.bpp == 24 && ma == 0xff000000)
@ -5263,7 +5352,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
if (info.hsz != 12) stbi__get8(s);
pal[i][3] = 255;
}
stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
if (info.bpp == 1) width = (s->img_x + 7) >> 3;
else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
else if (info.bpp == 8) width = s->img_x;
@ -5312,7 +5401,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
int z = 0;
int easy=0;
stbi__skip(s, info.offset - 14 - info.hsz);
stbi__skip(s, info.offset - info.extra_read - info.hsz);
if (info.bpp == 24) width = 3 * s->img_x;
else if (info.bpp == 16) width = 2*s->img_x;
else /* bpp = 32 and pad = 0 */ width=0;
@ -6202,7 +6291,7 @@ typedef struct
int w,h;
stbi_uc *out; // output buffer (always 4 components)
stbi_uc *background; // The current "background" as far as a gif is concerned
stbi_uc *history;
stbi_uc *history;
int flags, bgindex, ratio, transparent, eflags;
stbi_uc pal[256][4];
stbi_uc lpal[256][4];
@ -6290,7 +6379,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
{
stbi_uc *p, *c;
int idx;
int idx;
// recurse to decode the prefixes, since the linked-list is backwards,
// and working backwards through an interleaved image would be nasty
@ -6299,12 +6388,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
if (g->cur_y >= g->max_y) return;
idx = g->cur_x + g->cur_y;
idx = g->cur_x + g->cur_y;
p = &g->out[idx];
g->history[idx / 4] = 1;
g->history[idx / 4] = 1;
c = &g->color_table[g->codes[code].suffix * 4];
if (c[3] > 128) { // don't render transparent pixels;
if (c[3] > 128) { // don't render transparent pixels;
p[0] = c[2];
p[1] = c[1];
p[2] = c[0];
@ -6413,14 +6502,14 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
// two back is the image from two frames ago, used for a very specific disposal format
static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
{
int dispose;
int first_frame;
int pi;
int pcount;
int dispose;
int first_frame;
int pi;
int pcount;
STBI_NOTUSED(req_comp);
// on first frame, any non-written pixels get the background colour (non-transparent)
first_frame = 0;
first_frame = 0;
if (g->out == 0) {
if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))
@ -6432,17 +6521,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
if (!g->out || !g->background || !g->history)
return stbi__errpuc("outofmem", "Out of memory");
// image is treated as "transparent" at the start - ie, nothing overwrites the current background;
// image is treated as "transparent" at the start - ie, nothing overwrites the current background;
// background colour is only used for pixels that are not rendered first frame, after that "background"
// color refers to the color that was there the previous frame.
// color refers to the color that was there the previous frame.
memset(g->out, 0x00, 4 * pcount);
memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)
memset(g->history, 0x00, pcount); // pixels that were affected previous frame
first_frame = 1;
first_frame = 1;
} else {
// second frame - how do we dispoase of the previous one?
dispose = (g->eflags & 0x1C) >> 2;
pcount = g->w * g->h;
dispose = (g->eflags & 0x1C) >> 2;
pcount = g->w * g->h;
if ((dispose == 3) && (two_back == 0)) {
dispose = 2; // if I don't have an image to revert back to, default to the old background
@ -6451,32 +6540,32 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
if (dispose == 3) { // use previous graphic
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi]) {
memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
}
}
} else if (dispose == 2) {
// restore what was changed last frame to background before that frame;
} else if (dispose == 2) {
// restore what was changed last frame to background before that frame;
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi]) {
memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
}
}
} else {
// This is a non-disposal case eithe way, so just
// This is a non-disposal case eithe way, so just
// leave the pixels as is, and they will become the new background
// 1: do not dispose
// 0: not specified.
}
// background is what out is after the undoing of the previou frame;
memcpy( g->background, g->out, 4 * g->w * g->h );
// background is what out is after the undoing of the previou frame;
memcpy( g->background, g->out, 4 * g->w * g->h );
}
// clear my history;
// clear my history;
memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
for (;;) {
int tag = stbi__get8(s);
int tag = stbi__get8(s);
switch (tag) {
case 0x2C: /* Image Descriptor */
{
@ -6521,19 +6610,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
} else if (g->flags & 0x80) {
g->color_table = (stbi_uc *) g->pal;
} else
return stbi__errpuc("missing color table", "Corrupt GIF");
return stbi__errpuc("missing color table", "Corrupt GIF");
o = stbi__process_gif_raster(s, g);
if (!o) return NULL;
// if this was the first frame,
pcount = g->w * g->h;
// if this was the first frame,
pcount = g->w * g->h;
if (first_frame && (g->bgindex > 0)) {
// if first frame, any pixel not drawn to gets the background color
for (pi = 0; pi < pcount; ++pi) {
if (g->history[pi] == 0) {
g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
}
}
}
@ -6544,7 +6633,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
case 0x21: // Comment Extension.
{
int len;
int ext = stbi__get8(s);
int ext = stbi__get8(s);
if (ext == 0xF9) { // Graphic Control Extension.
len = stbi__get8(s);
if (len == 4) {
@ -6553,23 +6642,23 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
// unset old transparent
if (g->transparent >= 0) {
g->pal[g->transparent][3] = 255;
}
g->pal[g->transparent][3] = 255;
}
if (g->eflags & 0x01) {
g->transparent = stbi__get8(s);
if (g->transparent >= 0) {
g->pal[g->transparent][3] = 0;
g->pal[g->transparent][3] = 0;
}
} else {
// don't need transparent
stbi__skip(s, 1);
g->transparent = -1;
stbi__skip(s, 1);
g->transparent = -1;
}
} else {
stbi__skip(s, len);
break;
}
}
}
while ((len = stbi__get8(s)) != 0) {
stbi__skip(s, len);
}
@ -6588,15 +6677,15 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
{
if (stbi__gif_test(s)) {
int layers = 0;
int layers = 0;
stbi_uc *u = 0;
stbi_uc *out = 0;
stbi_uc *two_back = 0;
stbi_uc *two_back = 0;
stbi__gif g;
int stride;
int stride;
memset(&g, 0, sizeof(g));
if (delays) {
*delays = 0;
*delays = 0;
}
do {
@ -6606,44 +6695,52 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y,
if (u) {
*x = g.w;
*y = g.h;
++layers;
stride = g.w * g.h * 4;
++layers;
stride = g.w * g.h * 4;
if (out) {
out = (stbi_uc*) STBI_REALLOC( out, layers * stride );
void *tmp = (stbi_uc*) STBI_REALLOC( out, layers * stride );
if (NULL == tmp) {
STBI_FREE(g.out);
STBI_FREE(g.history);
STBI_FREE(g.background);
return stbi__errpuc("outofmem", "Out of memory");
}
else
out = (stbi_uc*) tmp;
if (delays) {
*delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers );
*delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers );
}
} else {
out = (stbi_uc*)stbi__malloc( layers * stride );
out = (stbi_uc*)stbi__malloc( layers * stride );
if (delays) {
*delays = (int*) stbi__malloc( layers * sizeof(int) );
*delays = (int*) stbi__malloc( layers * sizeof(int) );
}
}
memcpy( out + ((layers - 1) * stride), u, stride );
memcpy( out + ((layers - 1) * stride), u, stride );
if (layers >= 2) {
two_back = out - 2 * stride;
two_back = out - 2 * stride;
}
if (delays) {
(*delays)[layers - 1U] = g.delay;
(*delays)[layers - 1U] = g.delay;
}
}
} while (u != 0);
} while (u != 0);
// free temp buffer;
STBI_FREE(g.out);
STBI_FREE(g.history);
STBI_FREE(g.background);
// free temp buffer;
STBI_FREE(g.out);
STBI_FREE(g.history);
STBI_FREE(g.background);
// do the final conversion after loading everything;
// do the final conversion after loading everything;
if (req_comp && req_comp != 4)
out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
*z = layers;
*z = layers;
return out;
} else {
return stbi__errpuc("not GIF", "Image was not as a gif type.");
return stbi__errpuc("not GIF", "Image was not as a gif type.");
}
}
@ -6661,7 +6758,7 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req
*y = g.h;
// moved conversion to after successful load so that the same
// can be done for multiple frames.
// can be done for multiple frames.
if (req_comp && req_comp != 4)
u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
} else if (g.out) {
@ -6669,9 +6766,9 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req
STBI_FREE(g.out);
}
// free buffers needed for multiple frame loading;
// free buffers needed for multiple frame loading;
STBI_FREE(g.history);
STBI_FREE(g.background);
STBI_FREE(g.background);
return u;
}
@ -7334,7 +7431,7 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user
/*
revision history:
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
2.19 (2018-02-11) fix warning
2.18 (2018-01-30) fix warnings
2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug

View file

@ -20,8 +20,8 @@
output_pixels, out_w, out_h, 0,
num_channels , alpha_chan , 0)
stbir_resize_uint8_srgb_edgemode(
input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0,
input_pixels , in_w , in_h , 0,
output_pixels, out_w, out_h, 0,
num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP)
// WRAP/REFLECT/ZERO
@ -159,6 +159,7 @@
Nathan Reed: warning fixes
REVISIONS
0.97 (2020-02-02) fixed warning
0.96 (2019-03-04) fixed warnings
0.95 (2017-07-23) fixed warnings
0.94 (2017-03-18) fixed warnings
@ -233,7 +234,7 @@ STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , i
int num_channels);
// The following functions interpret image data as gamma-corrected sRGB.
// The following functions interpret image data as gamma-corrected sRGB.
// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
// or otherwise provide the index of the alpha channel. Flags value
// of 0 will probably do the right thing if you're not sure what
@ -306,19 +307,19 @@ typedef enum
STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context);
@ -350,7 +351,7 @@ STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context);
@ -358,7 +359,7 @@ STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context,
float x_scale, float y_scale,
@ -368,7 +369,7 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context,
float s0, float t0, float s1, float t1);
@ -670,14 +671,14 @@ static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
};
static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
{
static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
static const stbir__FP32 minval = { (127-13) << 23 };
stbir_uint32 tab,bias,scale,t;
stbir__FP32 f;
// Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
// The tests are carefully written so that NaNs map to 0, same as in the reference
// implementation.
@ -685,13 +686,13 @@ static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
in = minval.f;
if (in > almostone.f)
in = almostone.f;
// Do the table lookup and unpack bias, scale
f.f = in;
tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
bias = (tab >> 16) << 9;
scale = tab & 0xffff;
// Grab next-highest mantissa bits and perform linear interpolation
t = (f.u >> 12) & 0xff;
return (unsigned char) ((bias + scale*t) >> 16);
@ -1238,7 +1239,7 @@ static float* stbir__get_decode_buffer(stbir__info* stbir_info)
return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
}
#define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace))
#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
static void stbir__decode_scanline(stbir__info* stbir_info, int n)
{
@ -2445,7 +2446,7 @@ static int stbir__resize_arbitrary(
return 0;
result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
output_data, output_stride_in_bytes,
output_data, output_stride_in_bytes,
alpha_channel, flags, type,
edge_horizontal, edge_vertical,
colorspace, extra_memory, memory_required);
@ -2499,7 +2500,7 @@ STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels
STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context)
{
return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
@ -2511,7 +2512,7 @@ STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int
STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context)
{
return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
@ -2524,7 +2525,7 @@ STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int
STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
void *alloc_context)
{
return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
@ -2538,7 +2539,7 @@ STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context)
{
@ -2553,7 +2554,7 @@ STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context,
float x_scale, float y_scale,
@ -2574,7 +2575,7 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
stbir_datatype datatype,
int num_channels, int alpha_channel, int flags,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
stbir_filter filter_horizontal, stbir_filter filter_vertical,
stbir_colorspace space, void *alloc_context,
float s0, float t0, float s1, float t1)
@ -2593,38 +2594,38 @@ 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
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
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
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,
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
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
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.13 - public domain - http://nothings.org/stb
/* stb_image_write - v1.14 - public domain - http://nothings.org/stb
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
@ -105,7 +105,7 @@ USAGE:
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
data, set the global variable 'stbi_write_tga_with_rle' to 0.
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
Higher quality looks better but results in a bigger image.
JPEG baseline (no JPEG progressive).
@ -113,7 +113,7 @@ USAGE:
CREDITS:
Sean Barrett - PNG/BMP/TGA
Sean Barrett - PNG/BMP/TGA
Baldur Karlsson - HDR
Jean-Sebastien Guay - TGA monochrome
Tim Kelsey - misc enhancements
@ -247,17 +247,17 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi__flip_vertically_on_write=0;
static int stbi_write_png_compression_level = 8;
static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1;
#else
int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1;
#endif
static int stbi__flip_vertically_on_write = 0;
STBIWDEF void stbi_flip_vertically_on_write(int flag)
{
stbi__flip_vertically_on_write = flag;
@ -306,7 +306,7 @@ static FILE *stbiw__fopen(char const *filename, char const *mode)
wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
return 0;
@ -774,7 +774,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
#ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1]
@ -1044,13 +1044,13 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int
int type = mymap[filter_type];
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
if (type==0) {
memcpy(line_buffer, z, width*n);
return;
}
// first loop isn't optimized since it's just one pixel
// first loop isn't optimized since it's just one pixel
for (i = 0; i < n; ++i) {
switch (type) {
case 1: line_buffer[i] = z[i]; break;
@ -1271,26 +1271,31 @@ static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
bits[0] = val & ((1<<bits[1])-1);
}
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
int dataOff, i, diff, end0pos;
int dataOff, i, j, n, diff, end0pos, x, y;
int DU[64];
// DCT rows
for(dataOff=0; dataOff<64; dataOff+=8) {
for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
}
// DCT columns
for(dataOff=0; dataOff<8; ++dataOff) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]);
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],
&CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);
}
// Quantize/descale/zigzag the coefficients
for(i=0; i<64; ++i) {
float v = CDU[i]*fdtbl[i];
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
for(y = 0, j=0; y < 8; ++y) {
for(x = 0; x < 8; ++x,++j) {
float v;
i = y*du_stride+x;
v = CDU[i]*fdtbl[j];
// DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
}
}
// Encode DC
@ -1405,10 +1410,10 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
int row, col, i, k;
int row, col, i, k, subsample;
float fdtbl_Y[64], fdtbl_UV[64];
unsigned char YTable[64], UVTable[64];
@ -1417,6 +1422,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
}
quality = quality ? quality : 90;
subsample = quality <= 90 ? 1 : 0;
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
@ -1439,7 +1445,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
s->func(s->context, (void*)head0, sizeof(head0));
s->func(s->context, (void*)YTable, sizeof(YTable));
stbiw__putc(s, 1);
@ -1462,36 +1468,74 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
// Encode 8x8 macroblocks
{
static const unsigned short fillBits[] = {0x7F, 7};
const unsigned char *imageData = (const unsigned char *)data;
int DCY=0, DCU=0, DCV=0;
int bitBuf=0, bitCnt=0;
// comp == 2 is grey+alpha (alpha is ignored)
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
const unsigned char *dataR = (const unsigned char *)data;
const unsigned char *dataG = dataR + ofsG;
const unsigned char *dataB = dataR + ofsB;
int x, y, pos;
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
float YDU[64], UDU[64], VDU[64];
for(row = y, pos = 0; row < y+8; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+8; ++col, ++pos) {
float r, g, b;
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
if(subsample) {
for(y = 0; y < height; y += 16) {
for(x = 0; x < width; x += 16) {
float Y[256], U[256], V[256];
for(row = y, pos = 0; row < y+16; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+16; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
r = imageData[p+0];
g = imageData[p+ofsG];
b = imageData[p+ofsB];
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128;
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b;
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b;
// subsample U,V
{
float subU[64], subV[64];
int yy, xx;
for(yy = 0, pos = 0; yy < 8; ++yy) {
for(xx = 0; xx < 8; ++xx, ++pos) {
int j = yy*32+xx*2;
subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;
subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;
}
}
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
}
} else {
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
float Y[64], U[64], V[64];
for(row = y, pos = 0; row < y+8; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+8; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
}
@ -1530,10 +1574,13 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
1.13
1.12
1.11 (2019-08-11)
1.10 (2019-02-07)
support utf8 filenames in Windows; fix warnings and platform ifdefs
support utf8 filenames in Windows; fix warnings and platform ifdefs
1.09 (2018-02-11)
fix typo in zlib quality API, improve STB_I_W_STATIC in C++
1.08 (2018-01-29)
@ -1582,38 +1629,38 @@ 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
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
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
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,
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
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
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_perlin.h - v0.4 - perlin noise
// stb_perlin.h - v0.5 - perlin noise
// public domain single-file C implementation by Sean Barrett
//
// LICENSE
@ -47,9 +47,9 @@
//
// Fractal Noise:
//
// Three common fractal noise functions are included, which produce
// a wide variety of nice effects depending on the parameters
// provided. Note that each function will call stb_perlin_noise3
// Three common fractal noise functions are included, which produce
// a wide variety of nice effects depending on the parameters
// provided. Note that each function will call stb_perlin_noise3
// 'octaves' times, so this parameter will affect runtime.
//
// float stb_perlin_ridge_noise3(float x, float y, float z,
@ -66,7 +66,7 @@
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
// gain = 0.5 -- relative weighting applied to each successive octave
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
//
//
//
// Contributors:
// Jack Mott - additional noise functions
@ -78,6 +78,7 @@
extern "C" {
#endif
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_noise3_seed(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap, int seed);
extern float stb_perlin_ridge_noise3(float x, float y, float z, float lacunarity, float gain, float offset, int octaves);
extern float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves);
@ -94,41 +95,41 @@ extern float stb_perlin_noise3_wrap_nonpow2(float x, float y, float z, int x_wra
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
static unsigned char stb__perlin_randtab[512] =
{
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
// and a second copy so we don't need an extra mask or static initializer
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
};
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
};
// perlin's gradient has 12 cases so some get used 1/16th of the time
@ -297,7 +298,7 @@ float stb_perlin_fbm_noise3(float x, float y, float z, float lacunarity, float g
float frequency = 1.0f;
float amplitude = 1.0f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
sum += stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
frequency *= lacunarity;
@ -312,7 +313,7 @@ float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity,
float frequency = 1.0f;
float amplitude = 1.0f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
float r = stb_perlin_noise3_internal(x*frequency,y*frequency,z*frequency,0,0,0,(unsigned char)i)*amplitude;
sum += (float) fabs(r);
@ -390,38 +391,38 @@ 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
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
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
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,
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
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
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

@ -28,7 +28,7 @@
// Minor features
// Martins Mozeiko
// github:IntellectualKitty
//
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
// Fabian Giesen
@ -432,7 +432,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
}
}
tail = tail->next;
}
}
}
fr.prev_link = best;
@ -591,38 +591,38 @@ 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
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
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
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,
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
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
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,5 +1,14 @@
// stb_truetype.h - v1.22 - public domain
// authored from 2009-2019 by Sean Barrett / RAD Game Tools
// stb_truetype.h - v1.24 - public domain
// authored from 2009-2020 by Sean Barrett / RAD Game Tools
//
// =======================================================================
//
// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES
//
// This library does no range checking of the offsets found in the file,
// meaning an attacker can use it to read arbitrary memory.
//
// =======================================================================
//
// This library processes TrueType files:
// parse files
@ -32,11 +41,11 @@
// Daniel Ribeiro Maciel
//
// Bug/warning reports/fixes:
// "Zer" on mollyrocket Fabian "ryg" Giesen
// Cass Everitt Martins Mozeiko
// stoiko (Haemimont Games) Cap Petschulat
// Brian Hook Omar Cornut
// Walter van Niftrik github:aloucks
// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe
// Cass Everitt Martins Mozeiko github:aloucks
// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam
// Brian Hook Omar Cornut github:vassvik
// Walter van Niftrik Ryan Griege
// David Gow Peter LaValle
// David Given Sergey Popov
// Ivan-Assen Ivanov Giumo X. Clanjor
@ -44,13 +53,14 @@
// Johan Duparc Thomas Fields
// Hou Qiming Derek Vinyard
// Rob Loach Cort Stratton
// Kenney Phillis Jr. github:oyvindjam
// Brian Costabile github:vassvik
// Ken Voskuil (kaesve) Ryan Griege
//
// Kenney Phillis Jr. Brian Costabile
// Ken Voskuil (kaesve)
//
// VERSION HISTORY
//
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
// 1.24 (2020-02-05) fix warning
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
// 1.21 (2019-02-25) fix warning
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
@ -210,7 +220,7 @@
//
// Advancing for the next character:
// Call GlyphHMetrics, and compute 'current_point += SF * advance'.
//
//
//
// ADVANCED USAGE
//
@ -335,7 +345,7 @@ int main(int argc, char **argv)
}
return 0;
}
#endif
#endif
//
// Output:
//
@ -349,9 +359,9 @@ int main(int argc, char **argv)
// :@@. M@M
// @@@o@@@@
// :M@@V:@@.
//
//
//////////////////////////////////////////////////////////////////////////////
//
//
// Complete program: print "Hello World!" banner, with bugs
//
#if 0
@ -652,7 +662,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, cons
// Calling these functions in sequence is roughly equivalent to calling
// stbtt_PackFontRanges(). If you more control over the packing of multiple
// fonts, or if you want to pack custom data into a font texture, take a look
// at the source to of stbtt_PackFontRanges() and create a custom version
// at the source to of stbtt_PackFontRanges() and create a custom version
// using these functions, e.g. call GatherRects multiple times,
// building up a single array of rects, then call PackRects once,
// then call RenderIntoRects repeatedly. This may result in a
@ -704,7 +714,7 @@ struct stbtt_fontinfo
int numGlyphs; // number of glyphs, needed for range checking
int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf
int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf
int index_map; // a cmap mapping for our chosen character encoding
int indexToLocFormat; // format needed to map from glyph index to glyph
@ -787,6 +797,18 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1,
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
// as above, but takes one or more glyph indices for greater efficiency
typedef struct stbtt_kerningentry
{
int glyph1; // use stbtt_FindGlyphIndex
int glyph2;
int advance;
} stbtt_kerningentry;
STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info);
STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);
// Retrieves a complete list of all of the kerning pairs provided by the font
// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.
// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)
//////////////////////////////////////////////////////////////////////////////
//
@ -831,6 +853,11 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
// frees the data allocated above
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
// fills svg with the character's SVG data.
// returns data size or 0 if SVG not found.
//////////////////////////////////////////////////////////////////////////////
//
// BITMAP RENDERING
@ -960,7 +987,7 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa
// and computing from that can allow drop-out prevention).
//
// The algorithm has not been optimized at all, so expect it to be slow
// if computing lots of characters or very large sizes.
// if computing lots of characters or very large sizes.
@ -1332,6 +1359,22 @@ static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
return stbtt__cff_get_index(&cff);
}
// since most people won't use this, find this table the first time it's needed
static int stbtt__get_svg(stbtt_fontinfo *info)
{
stbtt_uint32 t;
if (info->svg < 0) {
t = stbtt__find_table(info->data, info->fontstart, "SVG ");
if (t) {
stbtt_uint32 offset = ttULONG(info->data + t + 2);
info->svg = t + offset;
} else {
info->svg = 0;
}
}
return info->svg;
}
static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
{
stbtt_uint32 cmap, t;
@ -1411,6 +1454,8 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in
else
info->numGlyphs = 0xffff;
info->svg = -1;
// find a cmap encoding table we understand *now* to avoid searching
// later. (todo: could make this installable)
// the same regardless of glyph.
@ -1717,7 +1762,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
if (i != 0)
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
// now start the new one
// now start the new one
start_off = !(flags & 1);
if (start_off) {
// if we start off with an off-curve point, then when we need to find a point on the curve
@ -1759,7 +1804,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
}
}
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
} else if (numberOfContours == -1) {
} else if (numberOfContours < 0) {
// Compound shapes.
int more = 1;
stbtt_uint8 *comp = data + g + 10;
@ -1770,7 +1815,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
int comp_num_verts = 0, i;
stbtt_vertex *comp_verts = 0, *tmp = 0;
float mtx[6] = {1,0,0,1,0,0}, m, n;
flags = ttSHORT(comp); comp+=2;
gidx = ttSHORT(comp); comp+=2;
@ -1800,7 +1845,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
}
// Find transformation scales.
m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
@ -1836,9 +1881,6 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
// More components ?
more = flags & (1<<5);
}
} else if (numberOfContours < 0) {
// @TODO other compound variations?
STBTT_assert(0);
} else {
// numberOfCounters == 0, do nothing
}
@ -2267,6 +2309,48 @@ STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_inde
}
}
STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info)
{
stbtt_uint8 *data = info->data + info->kern;
// we only look at the first table. it must be 'horizontal' and format 0.
if (!info->kern)
return 0;
if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
return 0;
if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
return 0;
return ttUSHORT(data+10);
}
STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)
{
stbtt_uint8 *data = info->data + info->kern;
int k, length;
// we only look at the first table. it must be 'horizontal' and format 0.
if (!info->kern)
return 0;
if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
return 0;
if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
return 0;
length = ttUSHORT(data+10);
if (table_length < length)
length = table_length;
for (k = 0; k < length; k++)
{
table[k].glyph1 = ttUSHORT(data+18+(k*6));
table[k].glyph2 = ttUSHORT(data+20+(k*6));
table[k].advance = ttSHORT(data+22+(k*6));
}
return length;
}
static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
{
stbtt_uint8 *data = info->data + info->kern;
@ -2603,6 +2687,45 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
STBTT_free(v, info->userdata);
}
STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)
{
int i;
stbtt_uint8 *data = info->data;
stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);
int numEntries = ttUSHORT(svg_doc_list);
stbtt_uint8 *svg_docs = svg_doc_list + 2;
for(i=0; i<numEntries; i++) {
stbtt_uint8 *svg_doc = svg_docs + (12 * i);
if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))
return svg_doc;
}
return 0;
}
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)
{
stbtt_uint8 *data = info->data;
stbtt_uint8 *svg_doc;
if (info->svg == 0)
return 0;
svg_doc = stbtt_FindSVGDoc(info, gl);
if (svg_doc != NULL) {
*svg = (char *) data + info->svg + ttULONG(svg_doc + 4);
return ttULONG(svg_doc + 8);
} else {
return 0;
}
}
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)
{
return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);
}
//////////////////////////////////////////////////////////////////////////////
//
// antialiasing software rasterizer
@ -2728,7 +2851,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
STBTT_assert(z != NULL);
if (!z) return z;
// round dx down to avoid overshooting
if (dxdy < 0)
z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
@ -2806,7 +2929,7 @@ static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__ac
}
}
}
e = e->next;
}
}
@ -3534,7 +3657,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info
{
int ix0,iy0,ix1,iy1;
stbtt__bitmap gbm;
stbtt_vertex *vertices;
stbtt_vertex *vertices;
int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
if (scale_x == 0) scale_x = scale_y;
@ -3557,7 +3680,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info
if (height) *height = gbm.h;
if (xoff ) *xoff = ix0;
if (yoff ) *yoff = iy0;
if (gbm.w && gbm.h) {
gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
if (gbm.pixels) {
@ -3568,7 +3691,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info
}
STBTT_free(vertices, info->userdata);
return gbm.pixels;
}
}
STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
{
@ -3580,7 +3703,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigne
int ix0,iy0;
stbtt_vertex *vertices;
int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
stbtt__bitmap gbm;
stbtt__bitmap gbm;
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
gbm.pixels = output;
@ -3602,7 +3725,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *
STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
{
return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
}
}
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
{
@ -3617,7 +3740,7 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns
STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
{
return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
}
}
STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
{
@ -3742,7 +3865,7 @@ static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *no
con->y = 0;
con->bottom_y = 0;
STBTT__NOTUSED(nodes);
STBTT__NOTUSED(num_nodes);
STBTT__NOTUSED(num_nodes);
}
static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
@ -4137,7 +4260,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char
n = 0;
for (i=0; i < num_ranges; ++i)
n += ranges[i].num_chars;
rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
if (rects == NULL)
return 0;
@ -4148,7 +4271,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char
n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
stbtt_PackFontRangesPackRects(spc, rects, n);
return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
STBTT_free(rects, spc->user_allocator_context);
@ -4309,7 +4432,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
if (x_inter < x)
if (x_inter < x)
winding += (y0 < y1) ? 1 : -1;
}
}
@ -4335,7 +4458,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
y1 = (int)verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
if (x_inter < x)
if (x_inter < x)
winding += (y0 < y1) ? 1 : -1;
}
} else {
@ -4347,7 +4470,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
if (hits[1][0] < 0)
winding += (hits[1][1] < 0 ? -1 : 1);
}
}
}
}
}
return winding;
@ -4423,7 +4546,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
// invert for y-downwards bitmaps
scale_y = -scale_y;
{
int x,y,i,j;
float *precompute;
@ -4572,7 +4695,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
STBTT_free(verts, info->userdata);
}
return data;
}
}
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
{
@ -4590,7 +4713,7 @@ STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
//
// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
{
stbtt_int32 i=0;
@ -4629,7 +4752,7 @@ static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, s
return i;
}
static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
{
return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
}
@ -4758,7 +4881,7 @@ STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
{
return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
}
STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
@ -4851,38 +4974,38 @@ 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
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
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
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,
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
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
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

@ -748,7 +748,7 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
fp = fopen(filename, "r");
if (!fp) {
fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno);
//fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno); // @raysan5: commented
return TINYOBJ_ERROR_FILE_OPERATION;
}
@ -1321,7 +1321,7 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
if (ret != TINYOBJ_SUCCESS) {
/* warning. */
fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret);
//fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret); // @raysan5: commented
}
TINYOBJ_FREE(filename);

View file

@ -24,7 +24,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2014-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -149,75 +149,75 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
#endif
#include <sys/time.h> // Required for: timespec
#include <time.h> // Required for: clock_gettime()
#include <sys/time.h> // Required for: timespec
#include <time.h> // Required for: clock_gettime()
#include <math.h> // Required for: atan2(), sqrt()
#include <stdint.h> // Required for: uint64_t
#include <math.h> // Required for: sqrtf(), atan2f()
#endif
#if defined(__APPLE__) // macOS also defines __MACH__
#include <mach/clock.h> // Required for: clock_get_time()
#include <mach/mach.h> // Required for: mach_timespec_t
#if defined(__APPLE__) // macOS also defines __MACH__
#include <mach/clock.h> // Required for: clock_get_time()
#include <mach/mach.h> // Required for: mach_timespec_t
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define FORCE_TO_SWIPE 0.0005f // Measured in normalized screen units/time
#define MINIMUM_DRAG 0.015f // Measured in normalized screen units (0.0f to 1.0f)
#define MINIMUM_PINCH 0.005f // Measured in normalized screen units (0.0f to 1.0f)
#define TAP_TIMEOUT 300 // Time in milliseconds
#define PINCH_TIMEOUT 300 // Time in milliseconds
#define DOUBLETAP_RANGE 0.03f // Measured in normalized screen units (0.0f to 1.0f)
#define FORCE_TO_SWIPE 0.0005f // Measured in normalized screen units/time
#define MINIMUM_DRAG 0.015f // Measured in normalized screen units (0.0f to 1.0f)
#define MINIMUM_PINCH 0.005f // Measured in normalized screen units (0.0f to 1.0f)
#define TAP_TIMEOUT 300 // Time in milliseconds
#define PINCH_TIMEOUT 300 // Time in milliseconds
#define DOUBLETAP_RANGE 0.03f // Measured in normalized screen units (0.0f to 1.0f)
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// ...
typedef struct {
int current; // Current detected gesture
unsigned int enabledFlags; // Enabled gestures flags
struct {
int firstId; // Touch id for first touch point
int pointCount; // Touch points counter
double eventTime; // Time stamp when an event happened
Vector2 upPosition; // Touch up position
Vector2 downPositionA; // First touch down position
Vector2 downPositionB; // Second touch down position
Vector2 downDragPosition; // Touch drag position
Vector2 moveDownPositionA; // First touch down position on move
Vector2 moveDownPositionB; // Second touch down position on move
int tapCounter; // TAP counter (one tap implies TOUCH_DOWN and TOUCH_UP actions)
} Touch;
struct {
bool resetRequired; // HOLD reset to get first touch point again
double timeDuration; // HOLD duration in milliseconds
} Hold;
struct {
Vector2 vector; // DRAG vector (between initial and current position)
float angle; // DRAG angle (relative to x-axis)
float distance; // DRAG distance (from initial touch point to final) (normalized [0..1])
float intensity; // DRAG intensity, how far why did the DRAG (pixels per frame)
} Drag;
struct {
bool start; // SWIPE used to define when start measuring GESTURES.Swipe.timeDuration
double timeDuration; // SWIPE time to calculate drag intensity
} Swipe;
struct {
Vector2 vector; // PINCH vector (between first and second touch points)
float angle; // PINCH angle (relative to x-axis)
float distance; // PINCH displacement distance (normalized [0..1])
} Pinch;
} GesturesData;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// Touch gesture variables
static Vector2 touchDownPosition = { 0.0f, 0.0f };
static Vector2 touchDownPosition2 = { 0.0f, 0.0f };
static Vector2 touchDownDragPosition = { 0.0f, 0.0f };
static Vector2 touchUpPosition = { 0.0f, 0.0f };
static Vector2 moveDownPosition = { 0.0f, 0.0f };
static Vector2 moveDownPosition2 = { 0.0f, 0.0f };
static int pointCount = 0; // Touch points counter
static int firstTouchId = -1; // Touch id for first touch point
static double eventTime = 0.0; // Time stamp when an event happened
// Tap gesture variables
static int tapCounter = 0; // TAP counter (one tap implies TOUCH_DOWN and TOUCH_UP actions)
// Hold gesture variables
static bool resetHold = false; // HOLD reset to get first touch point again
static double timeHold = 0.0f; // HOLD duration in milliseconds
// Drag gesture variables
static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position)
static float dragAngle = 0.0f; // DRAG angle (relative to x-axis)
static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) (normalized [0..1])
static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame)
// Swipe gestures variables
static bool startMoving = false; // SWIPE used to define when start measuring swipeTime
static double swipeTime = 0.0; // SWIPE time to calculate drag intensity
// Pinch gesture variables
static Vector2 pinchVector = { 0.0f , 0.0f }; // PINCH vector (between first and second touch points)
static float pinchAngle = 0.0f; // PINCH angle (relative to x-axis)
static float pinchDistance = 0.0f; // PINCH displacement distance (normalized [0..1])
static int currentGesture = GESTURE_NONE; // Current detected gesture
// Enabled gestures flags, all gestures enabled by default
static unsigned int enabledGestures = 0b0000001111111111;
static GesturesData GESTURES = {
.Touch.firstId = -1,
.current = GESTURE_NONE,
.enabledFlags = 0b0000001111111111 // All gestures enabled by default
};
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
@ -236,13 +236,13 @@ static double GetCurrentTime(void);
// Enable only desired getures to be detected
void SetGesturesEnabled(unsigned int gestureFlags)
{
enabledGestures = gestureFlags;
GESTURES.enabledFlags = gestureFlags;
}
// Check if a gesture have been detected
bool IsGestureDetected(int gesture)
{
if ((enabledGestures & currentGesture) == gesture) return true;
if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true;
else return false;
}
@ -250,150 +250,150 @@ bool IsGestureDetected(int gesture)
void ProcessGestureEvent(GestureEvent event)
{
// Reset required variables
pointCount = event.pointCount; // Required on UpdateGestures()
GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures()
if (pointCount < 2)
if (GESTURES.Touch.pointCount < 2)
{
if (event.touchAction == TOUCH_DOWN)
{
tapCounter++; // Tap counter
GESTURES.Touch.tapCounter++; // Tap counter
// Detect GESTURE_DOUBLE_TAP
if ((currentGesture == GESTURE_NONE) && (tapCounter >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE))
if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((GetCurrentTime() - GESTURES.Touch.eventTime) < TAP_TIMEOUT) && (Vector2Distance(GESTURES.Touch.downPositionA, event.position[0]) < DOUBLETAP_RANGE))
{
currentGesture = GESTURE_DOUBLETAP;
tapCounter = 0;
GESTURES.current = GESTURE_DOUBLETAP;
GESTURES.Touch.tapCounter = 0;
}
else // Detect GESTURE_TAP
{
tapCounter = 1;
currentGesture = GESTURE_TAP;
GESTURES.Touch.tapCounter = 1;
GESTURES.current = GESTURE_TAP;
}
touchDownPosition = event.position[0];
touchDownDragPosition = event.position[0];
GESTURES.Touch.downPositionA = event.position[0];
GESTURES.Touch.downDragPosition = event.position[0];
touchUpPosition = touchDownPosition;
eventTime = GetCurrentTime();
GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA;
GESTURES.Touch.eventTime = GetCurrentTime();
firstTouchId = event.pointerId[0];
GESTURES.Touch.firstId = event.pointerId[0];
dragVector = (Vector2){ 0.0f, 0.0f };
GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f };
}
else if (event.touchAction == TOUCH_UP)
{
if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0];
if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0];
// NOTE: dragIntensity dependend on the resolution of the screen
dragDistance = Vector2Distance(touchDownPosition, touchUpPosition);
dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime));
// NOTE: GESTURES.Drag.intensity dependend on the resolution of the screen
GESTURES.Drag.distance = Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((GetCurrentTime() - GESTURES.Swipe.timeDuration));
startMoving = false;
GESTURES.Swipe.start = false;
// Detect GESTURE_SWIPE
if ((dragIntensity > FORCE_TO_SWIPE) && (firstTouchId == event.pointerId[0]))
if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.Touch.firstId == event.pointerId[0]))
{
// NOTE: Angle should be inverted in Y
dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition);
GESTURES.Drag.angle = 360.0f - Vector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right
else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up
else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left
else if ((dragAngle > 210) && (dragAngle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down
else currentGesture = GESTURE_NONE;
if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right
else if ((GESTURES.Drag.angle > 30) && (GESTURES.Drag.angle < 120)) GESTURES.current = GESTURE_SWIPE_UP; // Up
else if ((GESTURES.Drag.angle > 120) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT; // Left
else if ((GESTURES.Drag.angle > 210) && (GESTURES.Drag.angle < 300)) GESTURES.current = GESTURE_SWIPE_DOWN; // Down
else GESTURES.current = GESTURE_NONE;
}
else
{
dragDistance = 0.0f;
dragIntensity = 0.0f;
dragAngle = 0.0f;
GESTURES.Drag.distance = 0.0f;
GESTURES.Drag.intensity = 0.0f;
GESTURES.Drag.angle = 0.0f;
currentGesture = GESTURE_NONE;
GESTURES.current = GESTURE_NONE;
}
touchDownDragPosition = (Vector2){ 0.0f, 0.0f };
pointCount = 0;
GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f };
GESTURES.Touch.pointCount = 0;
}
else if (event.touchAction == TOUCH_MOVE)
{
if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime();
if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.eventTime = GetCurrentTime();
if (!startMoving)
if (!GESTURES.Swipe.start)
{
swipeTime = GetCurrentTime();
startMoving = true;
GESTURES.Swipe.timeDuration = GetCurrentTime();
GESTURES.Swipe.start = true;
}
moveDownPosition = event.position[0];
GESTURES.Touch.moveDownPositionA = event.position[0];
if (currentGesture == GESTURE_HOLD)
if (GESTURES.current == GESTURE_HOLD)
{
if (resetHold) touchDownPosition = event.position[0];
if (GESTURES.Hold.resetRequired) GESTURES.Touch.downPositionA = event.position[0];
resetHold = false;
GESTURES.Hold.resetRequired = false;
// Detect GESTURE_DRAG
if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG)
if (Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_DRAG)
{
eventTime = GetCurrentTime();
currentGesture = GESTURE_DRAG;
GESTURES.Touch.eventTime = GetCurrentTime();
GESTURES.current = GESTURE_DRAG;
}
}
dragVector.x = moveDownPosition.x - touchDownDragPosition.x;
dragVector.y = moveDownPosition.y - touchDownDragPosition.y;
GESTURES.Drag.vector.x = GESTURES.Touch.moveDownPositionA.x - GESTURES.Touch.downDragPosition.x;
GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y;
}
}
else // Two touch points
{
if (event.touchAction == TOUCH_DOWN)
{
touchDownPosition = event.position[0];
touchDownPosition2 = event.position[1];
GESTURES.Touch.downPositionA = event.position[0];
GESTURES.Touch.downPositionB = event.position[1];
//pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2);
//GESTURES.Pinch.distance = Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB);
pinchVector.x = touchDownPosition2.x - touchDownPosition.x;
pinchVector.y = touchDownPosition2.y - touchDownPosition.y;
GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x;
GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y;
currentGesture = GESTURE_HOLD;
timeHold = GetCurrentTime();
GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = GetCurrentTime();
}
else if (event.touchAction == TOUCH_MOVE)
{
pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2);
GESTURES.Pinch.distance = Vector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
touchDownPosition = moveDownPosition;
touchDownPosition2 = moveDownPosition2;
GESTURES.Touch.downPositionA = GESTURES.Touch.moveDownPositionA;
GESTURES.Touch.downPositionB = GESTURES.Touch.moveDownPositionB;
moveDownPosition = event.position[0];
moveDownPosition2 = event.position[1];
GESTURES.Touch.moveDownPositionA = event.position[0];
GESTURES.Touch.moveDownPositionB = event.position[1];
pinchVector.x = moveDownPosition2.x - moveDownPosition.x;
pinchVector.y = moveDownPosition2.y - moveDownPosition.y;
GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x;
GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y;
if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH))
if ((Vector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (Vector2Distance(GESTURES.Touch.downPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH))
{
if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN;
else currentGesture = GESTURE_PINCH_OUT;
if ((Vector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) - GESTURES.Pinch.distance) < 0) GESTURES.current = GESTURE_PINCH_IN;
else GESTURES.current = GESTURE_PINCH_OUT;
}
else
{
currentGesture = GESTURE_HOLD;
timeHold = GetCurrentTime();
GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = GetCurrentTime();
}
// NOTE: Angle should be inverted in Y
pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2);
GESTURES.Pinch.angle = 360.0f - Vector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
}
else if (event.touchAction == TOUCH_UP)
{
pinchDistance = 0.0f;
pinchAngle = 0.0f;
pinchVector = (Vector2){ 0.0f, 0.0f };
pointCount = 0;
GESTURES.Pinch.distance = 0.0f;
GESTURES.Pinch.angle = 0.0f;
GESTURES.Pinch.vector = (Vector2){ 0.0f, 0.0f };
GESTURES.Touch.pointCount = 0;
currentGesture = GESTURE_NONE;
GESTURES.current = GESTURE_NONE;
}
}
}
@ -404,23 +404,23 @@ void UpdateGestures(void)
// NOTE: Gestures are processed through system callbacks on touch events
// Detect GESTURE_HOLD
if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && (pointCount < 2))
if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2))
{
currentGesture = GESTURE_HOLD;
timeHold = GetCurrentTime();
GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = GetCurrentTime();
}
if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2))
if (((GetCurrentTime() - GESTURES.Touch.eventTime) > TAP_TIMEOUT) && (GESTURES.current == GESTURE_DRAG) && (GESTURES.Touch.pointCount < 2))
{
currentGesture = GESTURE_HOLD;
timeHold = GetCurrentTime();
resetHold = true;
GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = GetCurrentTime();
GESTURES.Hold.resetRequired = true;
}
// Detect GESTURE_NONE
if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN))
if ((GESTURES.current == GESTURE_SWIPE_RIGHT) || (GESTURES.current == GESTURE_SWIPE_UP) || (GESTURES.current == GESTURE_SWIPE_LEFT) || (GESTURES.current == GESTURE_SWIPE_DOWN))
{
currentGesture = GESTURE_NONE;
GESTURES.current = GESTURE_NONE;
}
}
@ -429,14 +429,14 @@ int GetTouchPointsCount(void)
{
// NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called
return pointCount;
return GESTURES.Touch.pointCount;
}
// Get latest detected gesture
int GetGestureDetected(void)
{
// Get current gesture only if enabled
return (enabledGestures & currentGesture);
return (GESTURES.enabledFlags & GESTURES.current);
}
// Hold time measured in ms
@ -446,7 +446,7 @@ float GetGestureHoldDuration(void)
double time = 0.0;
if (currentGesture == GESTURE_HOLD) time = GetCurrentTime() - timeHold;
if (GESTURES.current == GESTURE_HOLD) time = GetCurrentTime() - GESTURES.Hold.timeDuration;
return (float)time;
}
@ -456,7 +456,7 @@ Vector2 GetGestureDragVector(void)
{
// NOTE: drag vector is calculated on one touch points TOUCH_MOVE
return dragVector;
return GESTURES.Drag.vector;
}
// Get drag angle
@ -465,16 +465,16 @@ float GetGestureDragAngle(void)
{
// NOTE: drag angle is calculated on one touch points TOUCH_UP
return dragAngle;
return GESTURES.Drag.angle;
}
// Get distance between two pinch points
Vector2 GetGesturePinchVector(void)
{
// NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index)
// NOTE: The position values used for GESTURES.Pinch.distance are not modified like the position values of [core.c]-->GetTouchPosition(int index)
// NOTE: pinch distance is calculated on two touch points TOUCH_MOVE
return pinchVector;
return GESTURES.Pinch.vector;
}
// Get angle beween two pinch points
@ -483,7 +483,7 @@ float GetGesturePinchAngle(void)
{
// NOTE: pinch angle is calculated on two touch points TOUCH_MOVE
return pinchAngle;
return GESTURES.Pinch.angle;
}
//----------------------------------------------------------------------------------
@ -532,7 +532,7 @@ static double GetCurrentTime(void)
// NOTE: Only for Linux-based systems
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds
unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds
time = ((double)nowTime/1000000.0); // Time in miliseconds
#endif
@ -548,7 +548,7 @@ static double GetCurrentTime(void)
// NOTE: OS X does not have clock_gettime(), using clock_get_time()
clock_get_time(cclock, &now);
mach_port_deallocate(mach_task_self(), cclock);
uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds
unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds
time = ((double)nowTime/1000000.0); // Time in miliseconds
#endif

View file

@ -17,7 +17,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -45,25 +45,46 @@
#include "utils.h" // Required for: fopen() Android mapping
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets()
#include <stdlib.h> // Required for: malloc(), free()
#include <string.h> // Required for: strcmp()
#include <math.h> // Required for: sin(), cos()
#include <stdio.h> // Required for: FILE, fopen(), fclose()
#include <string.h> // Required for: strncmp() [Used in LoadModelAnimations()], strlen() [Used in LoadTextureFromCgltfImage()]
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), fabsf()
#if defined(_WIN32)
#include <direct.h> // Required for: _chdir() [Used in LoadOBJ()]
#define CHDIR _chdir
#else
#include <unistd.h> // Required for: chdir() (POSIX) [Used in LoadOBJ()]
#define CHDIR chdir
#endif
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
#define TINYOBJ_MALLOC RL_MALLOC
#define TINYOBJ_CALLOC RL_CALLOC
#define TINYOBJ_REALLOC RL_REALLOC
#define TINYOBJ_FREE RL_FREE
#define TINYOBJ_LOADER_C_IMPLEMENTATION
#include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading
#endif
#if defined(SUPPORT_FILEFORMAT_GLTF)
#define CGLTF_MALLOC RL_MALLOC
#define CGLTF_FREE RL_FREE
#define CGLTF_IMPLEMENTATION
#include "external/cgltf.h" // glTF file format loading
#include "external/stb_image.h" // glTF texture images loading
#endif
#if defined(SUPPORT_MESH_GENERATION)
#define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T)))
#define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1))
#define PAR_REALLOC(T, BUF, N) ((T*)RL_REALLOC(BUF, sizeof(T)*(N)))
#define PAR_FREE RL_FREE
#define PAR_SHAPES_IMPLEMENTATION
#include "external/par_shapes.h" // Shapes 3d parametric generation
#endif
@ -110,11 +131,11 @@ void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
rlEnd();
}
// Draw a point in 3D space--actually a small line.
// Draw a point in 3D space, actually a small line
void DrawPoint3D(Vector3 position, Color color)
{
if (rlCheckBufferLimit(8)) rlglDraw();
rlPushMatrix();
rlTranslatef(position.x, position.y, position.z);
rlBegin(RL_LINES);
@ -664,11 +685,14 @@ Model LoadModel(const char *fileName)
if (model.meshCount == 0)
{
TraceLog(LOG_WARNING, "[%s] No meshes can be loaded, default to cube mesh", fileName);
model.meshCount = 1;
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
#if defined(SUPPORT_MESH_GENERATION)
TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data, default to cube mesh", fileName);
model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f);
#else
TRACELOG(LOG_WARNING, "MESH: [%s] Failed to load mesh data", fileName);
#endif
}
else
{
@ -678,7 +702,7 @@ Model LoadModel(const char *fileName)
if (model.materialCount == 0)
{
TraceLog(LOG_WARNING, "[%s] No materials can be loaded, default to white material", fileName);
TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to load material data, default to white material", fileName);
model.materialCount = 1;
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
@ -732,7 +756,7 @@ void UnloadModel(Model model)
RL_FREE(model.bones);
RL_FREE(model.bindPose);
TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM");
TRACELOG(LOG_INFO, "MODEL: Unloaded model from RAM and VRAM");
}
// Load meshes from model file
@ -806,8 +830,8 @@ void ExportMesh(Mesh mesh, const char *fileName)
}
else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export mesh vertex data
if (success) TraceLog(LOG_INFO, "Mesh exported successfully: %s", fileName);
else TraceLog(LOG_WARNING, "Mesh could not be exported.");
if (success) TRACELOG(LOG_INFO, "FILEIO: [%s] Mesh exported successfully", fileName);
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export mesh data", fileName);
}
// Load materials from model file
@ -825,7 +849,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
if (result != TINYOBJ_SUCCESS) {
TraceLog(LOG_WARNING, "[%s] Could not parse Materials file", fileName);
TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
}
// TODO: Process materials to return
@ -833,7 +857,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
tinyobj_materials_free(mats, count);
}
#else
TraceLog(LOG_WARNING, "[%s] Materials file not supported", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load material file", fileName);
#endif
// Set materials shader to default (DIFFUSE, SPECULAR, NORMAL)
@ -885,8 +909,8 @@ void SetMaterialTexture(Material *material, int mapType, Texture2D texture)
// Set the material for a mesh
void SetModelMeshMaterial(Model *model, int meshId, int materialId)
{
if (meshId >= model->meshCount) TraceLog(LOG_WARNING, "Mesh id greater than mesh count");
else if (materialId >= model->materialCount) TraceLog(LOG_WARNING,"Material id greater than material count");
if (meshId >= model->meshCount) TRACELOG(LOG_WARNING, "MESH: Id greater than mesh count");
else if (materialId >= model->materialCount) TRACELOG(LOG_WARNING, "MATERIAL: Id greater than material count");
else model->meshMaterial[meshId] = materialId;
}
@ -927,14 +951,15 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
unsigned int flags;
} IQMAnim;
FILE *iqmFile;
FILE *iqmFile = NULL;
IQMHeader iqm;
iqmFile = fopen(filename,"rb");
if (!iqmFile)
{
TraceLog(LOG_ERROR, "[%s] Unable to open file", filename);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", filename);
return NULL;
}
// Read IQM header
@ -942,17 +967,15 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
{
TraceLog(LOG_ERROR, "Magic Number \"%s\"does not match.", iqm.magic);
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", filename);
fclose(iqmFile);
return NULL;
}
if (iqm.version != IQM_VERSION)
{
TraceLog(LOG_ERROR, "IQM version %i is incorrect.", iqm.version);
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version incorrect", filename);
fclose(iqmFile);
return NULL;
}
@ -1089,7 +1112,7 @@ ModelAnimation *LoadModelAnimations(const char *filename, int *animCount)
animations[a].framePoses[frame][i].rotation = QuaternionMultiply(animations[a].framePoses[frame][animations[a].bones[i].parent].rotation, animations[a].framePoses[frame][i].rotation);
animations[a].framePoses[frame][i].translation = Vector3RotateByQuaternion(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].rotation);
animations[a].framePoses[frame][i].translation = Vector3Add(animations[a].framePoses[frame][i].translation, animations[a].framePoses[frame][animations[a].bones[i].parent].translation);
animations[a].framePoses[frame][i].scale = Vector3MultiplyV(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale);
animations[a].framePoses[frame][i].scale = Vector3Multiply(animations[a].framePoses[frame][i].scale, animations[a].framePoses[frame][animations[a].bones[i].parent].scale);
}
}
}
@ -1119,7 +1142,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
Vector3 inTranslation = { 0 };
Quaternion inRotation = { 0 };
Vector3 inScale = { 0 };
//Vector3 inScale = { 0 }; // Not used...
Vector3 outTranslation = { 0 };
Quaternion outRotation = { 0 };
@ -1134,7 +1157,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
boneId = model.meshes[m].boneIds[boneCounter];
inTranslation = model.bindPose[boneId].translation;
inRotation = model.bindPose[boneId].rotation;
inScale = model.bindPose[boneId].scale;
//inScale = model.bindPose[boneId].scale;
outTranslation = anim.framePoses[frame][boneId].translation;
outRotation = anim.framePoses[frame][boneId].rotation;
outScale = anim.framePoses[frame][boneId].scale;
@ -1142,7 +1165,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
// Vertices processing
// NOTE: We use meshes.vertices (default vertex position) to calculate meshes.animVertices (animated vertex position)
animVertex = (Vector3){ model.meshes[m].vertices[vCounter], model.meshes[m].vertices[vCounter + 1], model.meshes[m].vertices[vCounter + 2] };
animVertex = Vector3MultiplyV(animVertex, outScale);
animVertex = Vector3Multiply(animVertex, outScale);
animVertex = Vector3Subtract(animVertex, inTranslation);
animVertex = Vector3RotateByQuaternion(animVertex, QuaternionMultiply(outRotation, QuaternionInvert(inRotation)));
animVertex = Vector3Add(animVertex, outTranslation);
@ -1164,7 +1187,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
// Upload new vertex data to GPU for model drawing
rlUpdateBuffer(model.meshes[m].vboId[0], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex position
rlUpdateBuffer(model.meshes[m].vboId[2], model.meshes[m].animVertices, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex normals
rlUpdateBuffer(model.meshes[m].vboId[2], model.meshes[m].animNormals, model.meshes[m].vertexCount*3*sizeof(float)); // Update vertex normals
}
}
}
@ -1652,6 +1675,7 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
par_shapes_scale(cylinder, radius, radius, height);
par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
par_shapes_rotate(cylinder, PI/2.0f, (float[]){ 0, 1, 0 });
// Generate an orientable disk shape (top cap)
par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
@ -1814,6 +1838,11 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
Vector3 vA;
Vector3 vB;
Vector3 vC;
Vector3 vN;
for (int z = 0; z < mapZ-1; z++)
{
for (int x = 0; x < mapX-1; x++)
@ -1871,14 +1900,34 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
// Fill normals array with data
//--------------------------------------------------------------
for (int i = 0; i < 18; i += 3)
for (int i = 0; i < 18; i += 9)
{
mesh.normals[nCounter + i] = 0.0f;
mesh.normals[nCounter + i + 1] = 1.0f;
mesh.normals[nCounter + i + 2] = 0.0f;
}
vA.x = mesh.vertices[nCounter + i];
vA.y = mesh.vertices[nCounter + i + 1];
vA.z = mesh.vertices[nCounter + i + 2];
// TODO: Calculate normals in an efficient way
vB.x = mesh.vertices[nCounter + i + 3];
vB.y = mesh.vertices[nCounter + i + 4];
vB.z = mesh.vertices[nCounter + i + 5];
vC.x = mesh.vertices[nCounter + i + 6];
vC.y = mesh.vertices[nCounter + i + 7];
vC.z = mesh.vertices[nCounter + i + 8];
vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA)));
mesh.normals[nCounter + i] = vN.x;
mesh.normals[nCounter + i + 1] = vN.y;
mesh.normals[nCounter + i + 2] = vN.z;
mesh.normals[nCounter + i + 3] = vN.x;
mesh.normals[nCounter + i + 4] = vN.y;
mesh.normals[nCounter + i + 5] = vN.z;
mesh.normals[nCounter + i + 6] = vN.x;
mesh.normals[nCounter + i + 7] = vN.y;
mesh.normals[nCounter + i + 8] = vN.z;
}
nCounter += 18; // 6 vertex, 18 floats
trisCounter += 2;
@ -2289,7 +2338,7 @@ BoundingBox MeshBoundingBox(Mesh mesh)
void MeshTangents(Mesh *mesh)
{
if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
else TraceLog(LOG_WARNING, "Mesh tangents already exist");
else TRACELOG(LOG_WARNING, "MESH: Tangents data already available, re-writting");
Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
@ -2341,7 +2390,7 @@ void MeshTangents(Mesh *mesh)
// TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
#if defined(COMPUTE_TANGENTS_METHOD_01)
Vector3 tmp = Vector3Subtract(tangent, Vector3Multiply(normal, Vector3DotProduct(normal, tangent)));
Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
tmp = Vector3Normalize(tmp);
mesh->tangents[i*4 + 0] = tmp.x;
mesh->tangents[i*4 + 1] = tmp.y;
@ -2362,7 +2411,7 @@ void MeshTangents(Mesh *mesh)
// Load a new tangent attributes buffer
mesh->vboId[LOC_VERTEX_TANGENT] = rlLoadAttribBuffer(mesh->vaoId, LOC_VERTEX_TANGENT, mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
TraceLog(LOG_INFO, "Tangents computed for mesh");
TRACELOG(LOG_INFO, "MESH: Tangents data computed for provided mesh");
}
// Compute mesh binormals (aka bitangent)
@ -2370,12 +2419,11 @@ void MeshBinormals(Mesh *mesh)
{
for (int i = 0; i < mesh->vertexCount; i++)
{
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
float tangentW = mesh->tangents[i*4 + 3];
//Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
//Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
//Vector3 binormal = Vector3Scale(Vector3CrossProduct(normal, tangent), mesh->tangents[i*4 + 3]);
// TODO: Register computed binormal in mesh->binormal?
// Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW);
}
}
@ -2406,13 +2454,13 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
{
// TODO: Review color + tint premultiplication mechanism
Color color = model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color;
Color colorTint = WHITE;
colorTint.r = (((float)color.r/255.0)*((float)tint.r/255.0))*255;
colorTint.g = (((float)color.g/255.0)*((float)tint.g/255.0))*255;
colorTint.b = (((float)color.b/255.0)*((float)tint.b/255.0))*255;
colorTint.a = (((float)color.a/255.0)*((float)tint.a/255.0))*255;
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = colorTint;
rlDrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
model.materials[model.meshMaterial[i]].maps[MAP_DIFFUSE].color = color;
@ -2510,9 +2558,9 @@ void DrawBoundingBox(BoundingBox box, Color color)
{
Vector3 size;
size.x = (float)fabs(box.max.x - box.min.x);
size.y = (float)fabs(box.max.y - box.min.y);
size.z = (float)fabs(box.max.z - box.min.z);
size.x = fabsf(box.max.x - box.min.x);
size.y = fabsf(box.max.y - box.min.y);
size.z = fabsf(box.max.z - box.min.z);
Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f };
@ -2758,7 +2806,7 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
RayHitInfo result = { 0 };
if (fabs(ray.direction.y) > EPSILON)
if (fabsf(ray.direction.y) > EPSILON)
{
float distance = (ray.position.y - groundHeight)/-ray.direction.y;
@ -2791,32 +2839,20 @@ static Model LoadOBJ(const char *fileName)
tinyobj_material_t *materials = NULL;
unsigned int materialCount = 0;
int dataLength = 0;
char *data = NULL;
char *fileData = LoadFileText(fileName);
// Load model data
FILE *objFile = fopen(fileName, "rb");
if (objFile != NULL)
if (fileData != NULL)
{
fseek(objFile, 0, SEEK_END);
long length = ftell(objFile); // Get file size
fseek(objFile, 0, SEEK_SET); // Reset file pointer
int dataSize = strlen(fileData);
char currentDir[1024] = { 0 };
strcpy(currentDir, GetWorkingDirectory());
chdir(GetDirectoryPath(fileName));
data = (char *)RL_MALLOC(length);
fread(data, length, 1, objFile);
dataLength = length;
fclose(objFile);
}
if (data != NULL)
{
unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, data, dataLength, flags);
int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileData, dataSize, flags);
if (ret != TINYOBJ_SUCCESS) TraceLog(LOG_WARNING, "[%s] Model data could not be loaded", fileName);
else TraceLog(LOG_INFO, "[%s] Model data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount);
if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);
else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount);
// Init model meshes array
// TODO: Support multiple meshes... in the meantime, only one mesh is returned
@ -2866,8 +2902,6 @@ static Model LoadOBJ(const char *fileName)
tinyobj_vertex_index_t idx1 = attrib.faces[3*f + 1];
tinyobj_vertex_index_t idx2 = attrib.faces[3*f + 2];
// TraceLog(LOG_DEBUG, "Face %i index: v %i/%i/%i . vt %i/%i/%i . vn %i/%i/%i\n", f, idx0.v_idx, idx1.v_idx, idx2.v_idx, idx0.vt_idx, idx1.vt_idx, idx2.vt_idx, idx0.vn_idx, idx1.vn_idx, idx2.vn_idx);
// Fill vertices buffer (float) using vertex index of the face
for (int v = 0; v < 3; v++) { mesh.vertices[vCount + v] = attrib.vertices[idx0.v_idx*3 + v]; } vCount +=3;
for (int v = 0; v < 3; v++) { mesh.vertices[vCount + v] = attrib.vertices[idx1.v_idx*3 + v]; } vCount +=3;
@ -2916,7 +2950,7 @@ static Model LoadOBJ(const char *fileName)
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
// illumination model (see http://www.fileformat.info/format/material/)
// illumination model (Ref: http://www.fileformat.info/format/material/)
int illum;
int pad0;
@ -2953,13 +2987,12 @@ static Model LoadOBJ(const char *fileName)
tinyobj_attrib_free(&attrib);
tinyobj_shapes_free(meshes, meshCount);
tinyobj_materials_free(materials, materialCount);
RL_FREE(fileData);
RL_FREE(data);
chdir(currentDir);
}
// NOTE: At this point we have all model data loaded
TraceLog(LOG_INFO, "[%s] Model loaded successfully in RAM (CPU)", fileName);
return model;
}
#endif
@ -3046,7 +3079,7 @@ static Model LoadIQM(const char *fileName)
//-----------------------------------------------------------------------------------
// IQM vertex data types
typedef enum {
enum {
IQM_POSITION = 0,
IQM_TEXCOORD = 1,
IQM_NORMAL = 2,
@ -3055,11 +3088,11 @@ static Model LoadIQM(const char *fileName)
IQM_BLENDWEIGHTS = 5,
IQM_COLOR = 6, // NOTE: Vertex colors unused by default
IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default
} IQMVertexType;
};
Model model = { 0 };
FILE *iqmFile;
FILE *iqmFile = NULL;
IQMHeader iqm;
IQMMesh *imesh;
@ -3077,22 +3110,22 @@ static Model LoadIQM(const char *fileName)
if (iqmFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] IQM file could not be opened", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open IQM file", fileName);
return model;
}
fread(&iqm,sizeof(IQMHeader), 1, iqmFile); // Read IQM header
fread(&iqm, sizeof(IQMHeader), 1, iqmFile); // Read IQM header
if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
{
TraceLog(LOG_WARNING, "[%s] IQM file does not seem to be valid", fileName);
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName);
fclose(iqmFile);
return model;
}
if (iqm.version != IQM_VERSION)
{
TraceLog(LOG_WARNING, "[%s] IQM file version is not supported (%i).", fileName, iqm.version);
TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqm.version);
fclose(iqmFile);
return model;
}
@ -3283,7 +3316,7 @@ static Model LoadIQM(const char *fileName)
model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation);
model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation);
model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation);
model.bindPose[i].scale = Vector3MultiplyV(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
}
}
@ -3374,9 +3407,9 @@ static unsigned char *DecodeBase64(char *input, int *size)
}
// Load texture from cgltf_image
static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
static Image LoadImageFromCgltfImage(cgltf_image *image, const char *texPath, Color tint)
{
Texture texture = { 0 };
Image rimage = { 0 };
if (image->uri)
{
@ -3394,7 +3427,7 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
int i = 0;
while ((image->uri[i] != ',') && (image->uri[i] != 0)) i++;
if (image->uri[i] == 0) TraceLog(LOG_WARNING, "CGLTF Image: Invalid data URI");
if (image->uri[i] == 0) TRACELOG(LOG_WARNING, "IMAGE: glTF data URI is not a valid image");
else
{
int size;
@ -3403,22 +3436,18 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
int w, h;
unsigned char *raw = stbi_load_from_memory(data, size, &w, &h, NULL, 4);
Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
// TODO: Tint shouldn't be applied here!
ImageColorTint(&rimage, tint);
texture = LoadTextureFromImage(rimage);
UnloadImage(rimage);
}
}
else
{
Image rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
rimage = LoadImage(TextFormat("%s/%s", texPath, image->uri));
// TODO: Tint shouldn't be applied here!
ImageColorTint(&rimage, tint);
texture = LoadTextureFromImage(rimage);
UnloadImage(rimage);
}
}
else if (image->buffer_view)
@ -3437,41 +3466,36 @@ static Texture LoadTextureFromCgltfImage(cgltf_image *image, const char *texPath
unsigned char *raw = stbi_load_from_memory(data, image->buffer_view->size, &w, &h, NULL, 4);
free(data);
Image rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
rimage = LoadImagePro(raw, w, h, UNCOMPRESSED_R8G8B8A8);
free(raw);
// TODO: Tint shouldn't be applied here!
ImageColorTint(&rimage, tint);
texture = LoadTextureFromImage(rimage);
UnloadImage(rimage);
}
else
{
Image rimage = LoadImageEx(&tint, 1, 1);
texture = LoadTextureFromImage(rimage);
UnloadImage(rimage);
rimage = LoadImageEx(&tint, 1, 1);
}
return texture;
return rimage;
}
// Load glTF mesh data
// LoadGLTF loads in model data from given filename, supporting both .gltf and .glb
static Model LoadGLTF(const char *fileName)
{
/***********************************************************************************
Function implemented by Wilhem Barbier (@wbrbr)
Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
Features:
- Supports .gltf and .glb files
- Supports embedded (base64) or external textures
- Loads the albedo/diffuse texture (other maps could be added)
- Loads all raylib supported material textures, values and colors
- Supports multiple mesh per model and multiple primitives per model
Some restrictions (not exhaustive):
- Triangle-only meshes
- Not supported node hierarchies or transforms
- Only loads the diffuse texture... but not too hard to support other maps (normal, roughness/metalness...)
- Only supports unsigned short indices (no byte/unsigned int)
- Only supports float for texture coordinates (no byte/unsigned short)
@ -3496,7 +3520,7 @@ static Model LoadGLTF(const char *fileName)
if (gltfFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] glTF file could not be opened", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open glTF file", fileName);
return model;
}
@ -3516,11 +3540,12 @@ static Model LoadGLTF(const char *fileName)
if (result == cgltf_result_success)
{
TraceLog(LOG_INFO, "[%s][%s] Model meshes/materials: %i/%i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count);
TRACELOG(LOG_INFO, "MODEL: [%s] glTF meshes (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count);
TRACELOG(LOG_INFO, "MODEL: [%s] glTF materials (%s) count: %i", fileName, (data->file_type == 2)? "glb" : "gltf", data->meshes_count, data->materials_count);
// Read data buffers
result = cgltf_load_buffers(&options, data, fileName);
if (result != cgltf_result_success) TraceLog(LOG_INFO, "[%s][%s] Error loading mesh/material buffers", fileName, (data->file_type == 2)? "glb" : "gltf");
if (result != cgltf_result_success) TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load mesh/material buffers", fileName);
int primitivesCount = 0;
@ -3535,7 +3560,6 @@ static Model LoadGLTF(const char *fileName)
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VBO, sizeof(unsigned int));
//For each material
for (int i = 0; i < model.materialCount - 1; i++)
{
model.materials[i] = LoadMaterialDefault();
@ -3543,46 +3567,61 @@ static Model LoadGLTF(const char *fileName)
const char *texPath = GetDirectoryPath(fileName);
//Ensure material follows raylib support for PBR (metallic/roughness flow)
if (data->materials[i].has_pbr_metallic_roughness)
if (data->materials[i].has_pbr_metallic_roughness)
{
float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0] * 255);
tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1] * 255);
tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2] * 255);
tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3] * 255);
// NOTE: Material name not used for the moment
//if (model.materials[i].name && data->materials[i].name) strcpy(model.materials[i].name, data->materials[i].name);
model.materials[i].maps[MAP_ALBEDO].color = tint;
// TODO: REview: shouldn't these be *255 ???
tint.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
tint.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
tint.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
tint.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
model.materials[i].maps[MAP_ROUGHNESS].color = tint;
if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
if (data->materials[i].pbr_metallic_roughness.base_color_texture.texture)
{
model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
Image albedo = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.base_color_texture.texture->image, texPath, tint);
model.materials[i].maps[MAP_ALBEDO].texture = LoadTextureFromImage(albedo);
UnloadImage(albedo);
}
// NOTE: Tint isn't need for other textures.. pass null or clear?
// Just set as white, multiplying by white has no effect
tint = WHITE;
tint = WHITE; // Set tint to white after it's been used by Albedo
if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
{
model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
}
model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
model.materials[i].maps[MAP_METALNESS].value = metallic;
Image metallicRoughness = LoadImageFromCgltfImage(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture->image, texPath, tint);
model.materials[i].maps[MAP_ROUGHNESS].texture = LoadTextureFromImage(metallicRoughness);
if (data->materials[i].normal_texture.texture)
{
model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
float roughness = data->materials[i].pbr_metallic_roughness.roughness_factor;
model.materials[i].maps[MAP_ROUGHNESS].value = roughness;
float metallic = data->materials[i].pbr_metallic_roughness.metallic_factor;
model.materials[i].maps[MAP_METALNESS].value = metallic;
UnloadImage(metallicRoughness);
}
if (data->materials[i].occlusion_texture.texture)
if (data->materials[i].normal_texture.texture)
{
model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
Image normalImage = LoadImageFromCgltfImage(data->materials[i].normal_texture.texture->image, texPath, tint);
model.materials[i].maps[MAP_NORMAL].texture = LoadTextureFromImage(normalImage);
UnloadImage(normalImage);
}
if (data->materials[i].occlusion_texture.texture)
{
Image occulsionImage = LoadImageFromCgltfImage(data->materials[i].occlusion_texture.texture->image, texPath, tint);
model.materials[i].maps[MAP_OCCLUSION].texture = LoadTextureFromImage(occulsionImage);
UnloadImage(occulsionImage);
}
if (data->materials[i].emissive_texture.texture)
{
Image emissiveImage = LoadImageFromCgltfImage(data->materials[i].emissive_texture.texture->image, texPath, tint);
model.materials[i].maps[MAP_EMISSION].texture = LoadTextureFromImage(emissiveImage);
tint.r = (unsigned char)(data->materials[i].emissive_factor[0]*255);
tint.g = (unsigned char)(data->materials[i].emissive_factor[1]*255);
tint.b = (unsigned char)(data->materials[i].emissive_factor[2]*255);
model.materials[i].maps[MAP_EMISSION].color = tint;
UnloadImage(emissiveImage);
}
}
}
@ -3624,7 +3663,7 @@ static Model LoadGLTF(const char *fileName)
else
{
// TODO: Support normalized unsigned byte/unsigned short texture coordinates
TraceLog(LOG_WARNING, "[%s] Texture coordinates must be float", fileName);
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF texture coordinates must be float", fileName);
}
}
}
@ -3642,7 +3681,7 @@ static Model LoadGLTF(const char *fileName)
else
{
// TODO: Support unsigned byte/unsigned int
TraceLog(LOG_WARNING, "[%s] Indices must be unsigned short", fileName);
TRACELOG(LOG_WARNING, "MODEL: [%s] glTF index data must be unsigned short", fileName);
}
}
else
@ -3667,7 +3706,7 @@ static Model LoadGLTF(const char *fileName)
cgltf_free(data);
}
else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName);
else TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load glTF data", fileName);
RL_FREE(buffer);

File diff suppressed because it is too large Load diff

View file

@ -31,7 +31,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2014-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -189,6 +189,7 @@ bool IsAudioStreamPlaying(AudioStream stream); // Check if audi
void StopAudioStream(AudioStream stream); // Stop audio stream
void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
#ifdef __cplusplus
}

View file

@ -8,7 +8,7 @@
* - Written in plain C code (C99) in PascalCase/camelCase notation
* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2 - choose at compile)
* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl]
* - Powerful fonts module (XNA SpriteFonts, BMFonts, TTF)
* - Multiple Fonts formats supported (TTF, XNA fonts, AngelCode fonts)
* - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC)
* - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more!
* - Flexible Materials system, supporting classic maps and PBR maps
@ -52,7 +52,7 @@
* 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:
*
* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -74,14 +74,19 @@
#ifndef RAYLIB_H
#define RAYLIB_H
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
#define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll)
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
#define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
#if defined(_WIN32)
// Microsoft attibutes to tell compiler that symbols are imported/exported from a .dll
#if defined(BUILD_LIBTYPE_SHARED)
#define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll)
#elif defined(USE_LIBTYPE_SHARED)
#define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
#else
#define RLAPI // We are building or using raylib as a static library
#endif
#else
#define RLAPI // We are building or using raylib as a static library (or Linux shared library)
#define RLAPI // We are building or using raylib as a static library (or Linux shared library)
#endif
//----------------------------------------------------------------------------------
@ -103,8 +108,11 @@
#ifndef RL_CALLOC
#define RL_CALLOC(n,sz) calloc(n,sz)
#endif
#ifndef RL_REALLOC
#define RL_REALLOC(ptr,sz) realloc(ptr,sz)
#endif
#ifndef RL_FREE
#define RL_FREE(p) free(p)
#define RL_FREE(ptr) free(ptr)
#endif
// NOTE: MSC C++ compiler does not support compound literals (C99 feature)
@ -150,6 +158,7 @@
#define FormatText TextFormat
#define SubText TextSubtext
#define ShowWindow UnhideWindow
#define LoadText LoadFileText
//----------------------------------------------------------------------------------
// Structures Definition
@ -624,14 +633,16 @@ typedef enum {
// This is here just for error checking
GAMEPAD_BUTTON_UNKNOWN = 0,
// This is normally [A,B,X,Y]/[Circle,Triangle,Square,Cross]
// No support for 6 button controllers though..
// This is normally a DPAD
GAMEPAD_BUTTON_LEFT_FACE_UP,
GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
GAMEPAD_BUTTON_LEFT_FACE_DOWN,
GAMEPAD_BUTTON_LEFT_FACE_LEFT,
// This is normally a DPAD
// This normally corresponds with PlayStation and Xbox controllers
// XBOX: [Y,X,A,B]
// PS3: [Triangle,Square,Cross,Circle]
// No support for 6 button controllers though..
GAMEPAD_BUTTON_RIGHT_FACE_UP,
GAMEPAD_BUTTON_RIGHT_FACE_RIGHT,
GAMEPAD_BUTTON_RIGHT_FACE_DOWN,
@ -865,6 +876,7 @@ RLAPI bool IsWindowReady(void); // Check if wi
RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus)
RLAPI bool IsWindowResized(void); // Check if window has been resized
RLAPI bool IsWindowHidden(void); // Check if window is currently hidden
RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen
RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP)
RLAPI void UnhideWindow(void); // Show the window
RLAPI void HideWindow(void); // Hide the window
@ -912,6 +924,7 @@ RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a r
RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix)
RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Returns camera 2d transform matrix
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position
RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Returns size position for a 3d world space position
RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Returns the screen space position for a 2d camera world space position
RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Returns the world space position for a 2d camera screen space position
@ -940,6 +953,10 @@ RLAPI void TakeScreenshot(const char *fileName); // Takes a scr
RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
// Files management functions
RLAPI unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // Load file data as byte array (read)
RLAPI void SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write)
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
RLAPI void SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated
RLAPI bool FileExists(const char *fileName); // Check if file exists
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
@ -961,8 +978,8 @@ RLAPI unsigned char *CompressData(unsigned char *data, int dataLength, int *comp
RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength); // Decompress data (DEFLATE algorythm)
// Persistent storage management
RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position)
RLAPI int StorageLoadValue(int position); // Load integer value from storage file (from defined position)
RLAPI void SaveStorageValue(unsigned int position, int value); // Save integer value to storage file (to defined position)
RLAPI int LoadStorageValue(unsigned int position); // Load integer value from storage file (from defined position)
RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available)
@ -1050,6 +1067,8 @@ RLAPI void DrawCircleSectorLines(Vector2 center, float radius, int startAngle, i
RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-filled circle
RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version)
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse
RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline
RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAngle, int endAngle, int segments, Color color); // Draw ring
RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int startAngle, int endAngle, int segments, Color color); // Draw ring outline
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
@ -1068,8 +1087,7 @@ RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color);
RLAPI void DrawTriangleFan(Vector2 *points, int numPoints, Color color); // Draw a triangle fan defined by points (first vertex is the center)
RLAPI void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color); // Draw a triangle strip defined by points
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version)
RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Define default texture used to draw shapes
RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon outline of n sides
// Basic shapes collision detection functions
RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles
@ -1084,31 +1102,33 @@ RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Ve
// Texture Loading and Drawing Functions (Module: textures)
//------------------------------------------------------------------------------------
// Image/Texture2D data loading/unloading/saving functions
// Image loading functions
// NOTE: This functions do not require GPU access
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image from Color array data (RGBA - 32bit)
RLAPI Image LoadImagePro(void *data, int width, int height, int format); // Load image from raw data with parameters
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
RLAPI void ExportImage(Image image, const char *fileName); // Export image data to file
RLAPI void ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes
RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM)
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
RLAPI TextureCubemap LoadTextureCubemap(Image image, int layoutType); // Load cubemap from image, multiple image cubemap layouts supported
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot)
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
// Image generation functions
RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color
RLAPI Image GenImageGradientV(int width, int height, Color top, Color bottom); // Generate image: vertical gradient
RLAPI Image GenImageGradientH(int width, int height, Color left, Color right); // Generate image: horizontal gradient
RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient
RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked
RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise
RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise
RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm. Bigger tileSize means bigger cells
// Image manipulation functions
RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations)
RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font)
RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
@ -1121,14 +1141,6 @@ RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight);
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color); // Resize canvas and fill with color
RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
RLAPI Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount); // Extract color palette from image to maximum size (memory should be freed)
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font)
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
RLAPI void ImageDrawRectangle(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image
RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image
RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color); // Draw text (custom sprite font) within an image (destination)
RLAPI void ImageFlipVertical(Image *image); // Flip image vertically
RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally
RLAPI void ImageRotateCW(Image *image); // Rotate image clockwise 90deg
@ -1139,23 +1151,44 @@ RLAPI void ImageColorGrayscale(Image *image);
RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100)
RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255)
RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color
RLAPI Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount); // Extract color palette from image to maximum size (memory should be freed)
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
// Image generation functions
RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color
RLAPI Image GenImageGradientV(int width, int height, Color top, Color bottom); // Generate image: vertical gradient
RLAPI Image GenImageGradientH(int width, int height, Color left, Color right); // Generate image: horizontal gradient
RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient
RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked
RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise
RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise
RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm. Bigger tileSize means bigger cells
// Image drawing functions
// NOTE: Image software-rendering functions (CPU)
RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with given color
RLAPI void ImageDrawPixel(Image *dst, int posX, int posY, Color color); // Draw pixel within an image
RLAPI void ImageDrawPixelV(Image *dst, Vector2 position, Color color); // Draw pixel within an image (Vector version)
RLAPI void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw line within an image
RLAPI void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color); // Draw line within an image (Vector version)
RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle within an image
RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw circle within an image (Vector version)
RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image
RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version)
RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image
RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color); // Draw text (custom sprite font) within an image (destination)
// Texture2D configuration functions
// Texture loading functions
// NOTE: These functions require GPU access
RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM)
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
RLAPI TextureCubemap LoadTextureCubemap(Image image, int layoutType); // Load cubemap from image, multiple image cubemap layouts supported
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot)
// Texture configuration functions
RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture
RLAPI void SetTextureFilter(Texture2D texture, int filterMode); // Set texture scaling filter mode
RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); // Set texture wrapping mode
// Texture2D drawing functions
// Texture drawing functions
RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D
RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
@ -1164,6 +1197,9 @@ RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Re
RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
// Image/Texture misc functions
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
//------------------------------------------------------------------------------------
// Font Loading and Text Drawing Functions (Module: text)
//------------------------------------------------------------------------------------
@ -1183,15 +1219,17 @@ RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color co
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits
RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint,
int selectStart, int selectLength, Color selectText, Color selectBack); // Draw text using font inside rectangle limits with support for text selection
int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection
RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float scale, Color tint); // Draw one character (codepoint)
// Text misc. functions
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font
RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on font
RLAPI int GetGlyphIndex(Font font, int codepoint); // Get index position for a unicode character on font
// Text strings management functions (no utf8 strings, only byte chars)
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf style)
@ -1220,6 +1258,7 @@ RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength); // Encode
// Basic geometric 3D shapes drawing functions
RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space
RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line
RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube
RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version)
@ -1307,13 +1346,15 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);
//------------------------------------------------------------------------------------
// Shader loading/unloading functions
RLAPI char *LoadText(const char *fileName); // Load chars array from text file
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
RLAPI Shader GetShaderDefault(void); // Get default shader
RLAPI Texture2D GetTextureDefault(void); // Get default texture
RLAPI Texture2D GetShapesTexture(void); // Get texture to draw shapes
RLAPI Rectangle GetShapesTextureRec(void); // Get texture rectangle to draw shapes
RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Define default texture used to draw shapes
// Shader configuration functions
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
@ -1328,7 +1369,7 @@ RLAPI Matrix GetMatrixProjection(void); // Get
// Texture maps generation (PBR)
// NOTE: Required shaders should be provided
RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size); // Generate cubemap texture from HDR texture
RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D map, int size); // Generate cubemap texture from 2D texture
RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data
RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data
RLAPI Texture2D GenTextureBRDF(Shader shader, int size); // Generate BRDF texture
@ -1412,6 +1453,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
//------------------------------------------------------------------------------------
// Network (Module: network)

View file

@ -20,7 +20,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2015-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2015-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -135,7 +135,7 @@
typedef struct float3 { float v[3]; } float3;
typedef struct float16 { float v[16]; } float16;
#include <math.h> // Required for: sinf(), cosf(), tan(), fabs()
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), tan(), fabs()
//----------------------------------------------------------------------------------
// Module Functions Definition - Utils math
@ -268,6 +268,14 @@ RMDEF Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
return result;
}
// Rotate Vector by float in Degrees.
RMDEF Vector2 Vector2Rotate(Vector2 v, float degs)
{
float rads = degs*DEG2RAD;
Vector2 result = {v.x * cosf(rads) - v.y * sinf(rads) , v.x * sinf(rads) + v.y * cosf(rads) };
return result;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Vector3 math
//----------------------------------------------------------------------------------
@ -301,14 +309,14 @@ RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
}
// Multiply vector by scalar
RMDEF Vector3 Vector3Multiply(Vector3 v, float scalar)
RMDEF Vector3 Vector3Scale(Vector3 v, float scalar)
{
Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar };
return result;
}
// Multiply vector by vector
RMDEF Vector3 Vector3MultiplyV(Vector3 v1, Vector3 v2)
RMDEF Vector3 Vector3Multiply(Vector3 v1, Vector3 v2)
{
Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z };
return result;
@ -371,13 +379,6 @@ RMDEF float Vector3Distance(Vector3 v1, Vector3 v2)
return result;
}
// Scale provided vector
RMDEF Vector3 Vector3Scale(Vector3 v, float scale)
{
Vector3 result = { v.x*scale, v.y*scale, v.z*scale };
return result;
}
// Negate provided vector (invert direction)
RMDEF Vector3 Vector3Negate(Vector3 v)
{
@ -553,20 +554,18 @@ RMDEF float3 Vector3ToFloatV(Vector3 v)
// Compute matrix determinant
RMDEF float MatrixDeterminant(Matrix mat)
{
float result = { 0 };
// Cache the matrix values (speed optimization)
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
float result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
return result;
}
@ -1142,8 +1141,8 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
else
{
float halfTheta = (float) acos(cosHalfTheta);
float sinHalfTheta = (float) sqrt(1.0f - cosHalfTheta*cosHalfTheta);
float halfTheta = acosf(cosHalfTheta);
float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);
if (fabs(sinHalfTheta) < 0.001f)
{
@ -1198,7 +1197,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
if (trace > 0.0f)
{
float s = (float)sqrt(trace + 1)*2.0f;
float s = sqrtf(trace + 1)*2.0f;
float invS = 1.0f/s;
result.w = s*0.25f;
@ -1222,7 +1221,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
}
else if (m11 > m22)
{
float s = (float)sqrt(1.0f + m11 - m00 - m22)*2.0f;
float s = sqrtf(1.0f + m11 - m00 - m22)*2.0f;
float invS = 1.0f/s;
result.w = (mat.m8 - mat.m2)*invS;
@ -1232,7 +1231,7 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
}
else
{
float s = (float)sqrt(1.0f + m22 - m00 - m11)*2.0f;
float s = sqrtf(1.0f + m22 - m00 - m11)*2.0f;
float invS = 1.0f/s;
result.w = (mat.m1 - mat.m4)*invS;
@ -1322,10 +1321,8 @@ RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle
if (fabs(q.w) > 1.0f) q = QuaternionNormalize(q);
Vector3 resAxis = { 0.0f, 0.0f, 0.0f };
float resAngle = 0.0f;
resAngle = 2.0f*(float)acos(q.w);
float den = (float)sqrt(1.0f - q.w*q.w);
float resAngle = 2.0f*acosf(q.w);
float den = sqrtf(1.0f - q.w*q.w);
if (den > 0.0001f)
{

File diff suppressed because it is too large Load diff

775
raylib/rmem.h Normal file
View file

@ -0,0 +1,775 @@
/**********************************************************************************************
*
* rmem - raylib memory pool and objects pool
*
* A quick, efficient, and minimal free list and stack-based allocator
*
* PURPOSE:
* - A quicker, efficient memory allocator alternative to 'malloc' and friends.
* - Reduce the possibilities of memory leaks for beginner developers using Raylib.
* - Being able to flexibly range check memory if necessary.
*
* CONFIGURATION:
*
* #define RMEM_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2019 Kevin 'Assyrianic' Yonan (@assyrianic) and reviewed by Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef RMEM_H
#define RMEM_H
#include <inttypes.h>
#include <stdbool.h>
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
#define RMEMAPI __declspec(dllexport) // We are building library as a Win32 shared library (.dll)
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
#define RMEMAPI __declspec(dllimport) // We are using library as a Win32 shared library (.dll)
#else
#define RMEMAPI // We are building or using library as a static library (or Linux shared library)
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Memory Pool
typedef struct MemNode MemNode;
struct MemNode {
size_t size;
MemNode *next, *prev;
};
typedef struct AllocList {
MemNode *head, *tail;
size_t len, maxNodes;
bool autoDefrag : 1;
} AllocList;
typedef struct Stack {
uint8_t *mem, *base;
size_t size;
} Stack;
#define MEMPOOL_BUCKET_SIZE 8
#define MEMPOOL_BUCKET_BITS 3
typedef struct MemPool {
AllocList freeList;
Stack stack;
MemNode *buckets[MEMPOOL_BUCKET_SIZE];
} MemPool;
// Object Pool
typedef struct ObjPool {
Stack stack;
size_t objSize, freeBlocks;
} ObjPool;
// Double-Ended Stack aka Deque
typedef struct BiStack {
uint8_t *mem, *front, *back;
size_t size;
} BiStack;
#if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions
#endif
//------------------------------------------------------------------------------------
// Functions Declaration - Memory Pool
//------------------------------------------------------------------------------------
RMEMAPI MemPool CreateMemPool(size_t bytes);
RMEMAPI MemPool CreateMemPoolFromBuffer(void *buf, size_t bytes);
RMEMAPI void DestroyMemPool(MemPool *mempool);
RMEMAPI void *MemPoolAlloc(MemPool *mempool, size_t bytes);
RMEMAPI void *MemPoolRealloc(MemPool *mempool, void *ptr, size_t bytes);
RMEMAPI void MemPoolFree(MemPool *mempool, void *ptr);
RMEMAPI void MemPoolCleanUp(MemPool *mempool, void **ptrref);
RMEMAPI void MemPoolReset(MemPool *mempool);
RMEMAPI bool MemPoolDefrag(MemPool *mempool);
RMEMAPI size_t GetMemPoolFreeMemory(const MemPool mempool);
RMEMAPI void ToggleMemPoolAutoDefrag(MemPool *mempool);
//------------------------------------------------------------------------------------
// Functions Declaration - Object Pool
//------------------------------------------------------------------------------------
RMEMAPI ObjPool CreateObjPool(size_t objsize, size_t len);
RMEMAPI ObjPool CreateObjPoolFromBuffer(void *buf, size_t objsize, size_t len);
RMEMAPI void DestroyObjPool(ObjPool *objpool);
RMEMAPI void *ObjPoolAlloc(ObjPool *objpool);
RMEMAPI void ObjPoolFree(ObjPool *objpool, void *ptr);
RMEMAPI void ObjPoolCleanUp(ObjPool *objpool, void **ptrref);
//------------------------------------------------------------------------------------
// Functions Declaration - Double-Ended Stack
//------------------------------------------------------------------------------------
RMEMAPI BiStack CreateBiStack(size_t len);
RMEMAPI BiStack CreateBiStackFromBuffer(void *buf, size_t len);
RMEMAPI void DestroyBiStack(BiStack *destack);
RMEMAPI void *BiStackAllocFront(BiStack *destack, size_t len);
RMEMAPI void *BiStackAllocBack(BiStack *destack, size_t len);
RMEMAPI void BiStackResetFront(BiStack *destack);
RMEMAPI void BiStackResetBack(BiStack *destack);
RMEMAPI void BiStackResetAll(BiStack *destack);
RMEMAPI intptr_t BiStackMargins(BiStack destack);
#ifdef __cplusplus
}
#endif
#endif // RMEM_H
/***********************************************************************************
*
* RMEM IMPLEMENTATION
*
************************************************************************************/
#if defined(RMEM_IMPLEMENTATION)
#include <stdio.h> // Required for: malloc(), calloc(), free()
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// Make sure restrict type qualifier for pointers is defined
// NOTE: Not supported by C++, it is a C only keyword
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) || defined(_MSC_VER)
#ifndef restrict
#define restrict __restrict
#endif
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// ...
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static inline size_t __AlignSize(const size_t size, const size_t align)
{
return (size + (align - 1)) & -align;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Memory Pool
//----------------------------------------------------------------------------------
MemPool CreateMemPool(const size_t size)
{
MemPool mempool = { 0 };
if (size == 0UL) return mempool;
else
{
// Align the mempool size to at least the size of an alloc node.
mempool.stack.size = size;
mempool.stack.mem = malloc(mempool.stack.size*sizeof *mempool.stack.mem);
if (mempool.stack.mem == NULL)
{
mempool.stack.size = 0UL;
return mempool;
}
else
{
mempool.stack.base = mempool.stack.mem + mempool.stack.size;
return mempool;
}
}
}
MemPool CreateMemPoolFromBuffer(void *buf, const size_t size)
{
MemPool mempool = { 0 };
if ((size == 0UL) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
else
{
mempool.stack.size = size;
mempool.stack.mem = buf;
mempool.stack.base = mempool.stack.mem + mempool.stack.size;
return mempool;
}
}
void DestroyMemPool(MemPool *const mempool)
{
if ((mempool == NULL) || (mempool->stack.mem == NULL)) return;
else
{
free(mempool->stack.mem);
*mempool = (MemPool){ 0 };
}
}
void *MemPoolAlloc(MemPool *const mempool, const size_t size)
{
if ((mempool == NULL) || (size == 0UL) || (size > mempool->stack.size)) return NULL;
else
{
MemNode *new_mem = NULL;
const size_t ALLOC_SIZE = __AlignSize(size + sizeof *new_mem, sizeof(intptr_t));
const size_t BUCKET_INDEX = (ALLOC_SIZE >> MEMPOOL_BUCKET_BITS) - 1;
// If the size is small enough, let's check if our buckets has a fitting memory block.
if ((BUCKET_INDEX < MEMPOOL_BUCKET_SIZE) &&
(mempool->buckets[BUCKET_INDEX] != NULL) &&
(mempool->buckets[BUCKET_INDEX]->size >= ALLOC_SIZE))
{
new_mem = mempool->buckets[BUCKET_INDEX];
mempool->buckets[BUCKET_INDEX] = mempool->buckets[BUCKET_INDEX]->next;
if( mempool->buckets[BUCKET_INDEX] != NULL )
mempool->buckets[BUCKET_INDEX]->prev = NULL;
}
else if (mempool->freeList.head != NULL)
{
const size_t MEM_SPLIT_THRESHOLD = 16;
// If the freelist is valid, let's allocate FROM the freelist then!
for (MemNode *inode = mempool->freeList.head; inode != NULL; inode = inode->next)
{
if (inode->size < ALLOC_SIZE) continue;
else if (inode->size <= (ALLOC_SIZE + MEM_SPLIT_THRESHOLD))
{
// Close in size - reduce fragmentation by not splitting.
new_mem = inode;
(inode->prev != NULL)? (inode->prev->next = inode->next) : (mempool->freeList.head = inode->next);
(inode->next != NULL)? (inode->next->prev = inode->prev) : (mempool->freeList.tail = inode->prev);
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
else mempool->freeList.tail = NULL;
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
mempool->freeList.len--;
break;
}
else
{
// Split the memory chunk.
new_mem = (MemNode *)((uint8_t *)inode + (inode->size - ALLOC_SIZE));
inode->size -= ALLOC_SIZE;
new_mem->size = ALLOC_SIZE;
break;
}
}
}
if (new_mem == NULL)
{
// not enough memory to support the size!
if ((mempool->stack.base - ALLOC_SIZE) < mempool->stack.mem) return NULL;
else
{
// Couldn't allocate from a freelist, allocate from available mempool.
// Subtract allocation size from the mempool.
mempool->stack.base -= ALLOC_SIZE;
// Use the available mempool space as the new node.
new_mem = (MemNode *)mempool->stack.base;
new_mem->size = ALLOC_SIZE;
}
}
// Visual of the allocation block.
// --------------
// | mem size | lowest addr of block
// | next node | 12 byte (32-bit) header
// | prev node | 24 byte (64-bit) header
// --------------
// | alloc'd |
// | memory |
// | space | highest addr of block
// --------------
new_mem->next = new_mem->prev = NULL;
uint8_t *const final_mem = (uint8_t *)new_mem + sizeof *new_mem;
return memset(final_mem, 0, new_mem->size - sizeof *new_mem);
}
}
void *MemPoolRealloc(MemPool *const restrict mempool, void *ptr, const size_t size)
{
if ((mempool == NULL) || (size > mempool->stack.size)) return NULL;
// NULL ptr should make this work like regular Allocation.
else if (ptr == NULL) return MemPoolAlloc(mempool, size);
else if ((uintptr_t)ptr - sizeof(MemNode) < (uintptr_t)mempool->stack.mem) return NULL;
else
{
MemNode *const node = (MemNode *)((uint8_t *)ptr - sizeof *node);
const size_t NODE_SIZE = sizeof *node;
uint8_t *const resized_block = MemPoolAlloc(mempool, size);
if (resized_block == NULL) return NULL;
else
{
MemNode *const resized = (MemNode *)(resized_block - sizeof *resized);
memmove(resized_block, ptr, (node->size > resized->size)? (resized->size - NODE_SIZE) : (node->size - NODE_SIZE));
MemPoolFree(mempool, ptr);
return resized_block;
}
}
}
void MemPoolFree(MemPool *const restrict mempool, void *ptr)
{
if ((mempool == NULL) || (ptr == NULL) || ((uintptr_t)ptr - sizeof(MemNode) < (uintptr_t)mempool->stack.mem)) return;
else
{
// Behind the actual pointer data is the allocation info.
MemNode *const mem_node = (MemNode *)((uint8_t *)ptr - sizeof *mem_node);
const size_t BUCKET_INDEX = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1;
// Make sure the pointer data is valid.
if (((uintptr_t)mem_node < (uintptr_t)mempool->stack.base) ||
(((uintptr_t)mem_node - (uintptr_t)mempool->stack.mem) > mempool->stack.size) ||
(mem_node->size == 0UL) ||
(mem_node->size > mempool->stack.size)) return;
// If the mem_node is right at the stack base ptr, then add it to the stack.
else if ((uintptr_t)mem_node == (uintptr_t)mempool->stack.base)
{
mempool->stack.base += mem_node->size;
}
// attempted stack merge failed, try to place it into the memnode buckets
else if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE)
{
if (mempool->buckets[BUCKET_INDEX] == NULL) mempool->buckets[BUCKET_INDEX] = mem_node;
else
{
for (MemNode *n = mempool->buckets[BUCKET_INDEX]; n != NULL; n = n->next) if( n==mem_node ) return;
mempool->buckets[BUCKET_INDEX]->prev = mem_node;
mem_node->next = mempool->buckets[BUCKET_INDEX];
mempool->buckets[BUCKET_INDEX] = mem_node;
}
}
// Otherwise, we add it to the free list.
// We also check if the freelist already has the pointer so we can prevent double frees.
else /*if ((mempool->freeList.len == 0UL) || ((uintptr_t)mempool->freeList.head >= (uintptr_t)mempool->stack.mem && (uintptr_t)mempool->freeList.head - (uintptr_t)mempool->stack.mem < mempool->stack.size))*/
{
for (MemNode *n = mempool->freeList.head; n != NULL; n = n->next) if (n == mem_node) return;
// This code insertion sorts where largest size is last.
if (mempool->freeList.head == NULL)
{
mempool->freeList.head = mempool->freeList.tail = mem_node;
mempool->freeList.len++;
}
else if (mempool->freeList.head->size >= mem_node->size)
{
mem_node->next = mempool->freeList.head;
mem_node->next->prev = mem_node;
mempool->freeList.head = mem_node;
mempool->freeList.len++;
}
else //if (mempool->freeList.tail->size <= mem_node->size)
{
mem_node->prev = mempool->freeList.tail;
mempool->freeList.tail->next = mem_node;
mempool->freeList.tail = mem_node;
mempool->freeList.len++;
}
if (mempool->freeList.autoDefrag && (mempool->freeList.maxNodes != 0UL) && (mempool->freeList.len > mempool->freeList.maxNodes)) MemPoolDefrag(mempool);
}
}
}
void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref)
{
if ((mempool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return;
else
{
MemPoolFree(mempool, *ptrref);
*ptrref = NULL;
}
}
size_t GetMemPoolFreeMemory(const MemPool mempool)
{
size_t total_remaining = (uintptr_t)mempool.stack.base - (uintptr_t)mempool.stack.mem;
for (MemNode *n = mempool.freeList.head; n != NULL; n = n->next) total_remaining += n->size;
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++) for (MemNode *n = mempool.buckets[i]; n != NULL; n = n->next) total_remaining += n->size;
return total_remaining;
}
void MemPoolReset(MemPool *const mempool)
{
if (mempool == NULL) return;
mempool->freeList.head = mempool->freeList.tail = NULL;
mempool->freeList.len = 0;
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++) mempool->buckets[i] = NULL;
mempool->stack.base = mempool->stack.mem + mempool->stack.size;
}
bool MemPoolDefrag(MemPool *const mempool)
{
if (mempool == NULL) return false;
else
{
// If the memory pool has been entirely released, fully defrag it.
if (mempool->stack.size == GetMemPoolFreeMemory(*mempool))
{
MemPoolReset(mempool);
return true;
}
else
{
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++)
{
while (mempool->buckets[i] != NULL)
{
if ((uintptr_t)mempool->buckets[i] == (uintptr_t)mempool->stack.base)
{
mempool->stack.base += mempool->buckets[i]->size;
mempool->buckets[i]->size = 0;
mempool->buckets[i] = mempool->buckets[i]->next;
if (mempool->buckets[i] != NULL) mempool->buckets[i]->prev = NULL;
}
else break;
}
}
const size_t PRE_DEFRAG_LEN = mempool->freeList.len;
MemNode **node = &mempool->freeList.head;
while (*node != NULL)
{
if ((uintptr_t)*node == (uintptr_t)mempool->stack.base)
{
// If node is right at the stack, merge it back into the stack.
mempool->stack.base += (*node)->size;
(*node)->size = 0UL;
((*node)->prev != NULL)? ((*node)->prev->next = (*node)->next) : (mempool->freeList.head = (*node)->next);
((*node)->next != NULL)? ((*node)->next->prev = (*node)->prev) : (mempool->freeList.tail = (*node)->prev);
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
else mempool->freeList.tail = NULL;
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else if (((uintptr_t)*node + (*node)->size) == (uintptr_t)(*node)->next)
{
// Next node is at a higher address.
(*node)->size += (*node)->next->size;
(*node)->next->size = 0UL;
// <-[P Curr N]-> <-[P Next N]-> <-[P NextNext N]->
//
// |--------------------|
// <-[P Curr N]-> <-[P Next N]-> [P NextNext N]->
if ((*node)->next->next != NULL) (*node)->next->next->prev = *node;
// <-[P Curr N]-> <-[P NextNext N]->
(*node)->next = (*node)->next->next;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else if ((((uintptr_t)*node + (*node)->size) == (uintptr_t)(*node)->prev) && ((*node)->prev->prev != NULL))
{
// Prev node is at a higher address.
(*node)->size += (*node)->prev->size;
(*node)->prev->size = 0UL;
// <-[P PrevPrev N]-> <-[P Prev N]-> <-[P Curr N]->
//
// |--------------------|
// <-[P PrevPrev N] <-[P Prev N]-> <-[P Curr N]->
(*node)->prev->prev->next = *node;
// <-[P PrevPrev N]-> <-[P Curr N]->
(*node)->prev = (*node)->prev->prev;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else if ((*node)->prev != NULL && (*node)->next != NULL && (uintptr_t)*node - (*node)->next->size == (uintptr_t)(*node)->next)
{
// Next node is at a lower address.
(*node)->next->size += (*node)->size;
(*node)->size = 0UL;
(*node)->next->prev = (*node)->prev;
(*node)->prev->next = (*node)->next;
*node = (*node)->next;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else if ((*node)->prev != NULL && (*node)->next != NULL && (uintptr_t)*node - (*node)->prev->size == (uintptr_t)(*node)->prev)
{
// Prev node is at a lower address.
(*node)->prev->size += (*node)->size;
(*node)->size = 0UL;
(*node)->next->prev = (*node)->prev;
(*node)->prev->next = (*node)->next;
*node = (*node)->prev;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else
{
node = &(*node)->next;
}
}
return PRE_DEFRAG_LEN > mempool->freeList.len;
}
}
}
void ToggleMemPoolAutoDefrag(MemPool *const mempool)
{
if (mempool == NULL) return;
else mempool->freeList.autoDefrag ^= true;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Object Pool
//----------------------------------------------------------------------------------
union ObjInfo {
uint8_t *const byte;
size_t *const index;
};
ObjPool CreateObjPool(const size_t objsize, const size_t len)
{
ObjPool objpool = { 0 };
if ((len == 0UL) || (objsize == 0UL)) return objpool;
else
{
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
objpool.stack.size = objpool.freeBlocks = len;
objpool.stack.mem = calloc(objpool.stack.size, objpool.objSize);
if (objpool.stack.mem == NULL)
{
objpool.stack.size = 0UL;
return objpool;
}
else
{
for (int i = 0; i < objpool.freeBlocks; i++)
{
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
*block.index = i + 1;
}
objpool.stack.base = objpool.stack.mem;
return objpool;
}
}
}
ObjPool CreateObjPoolFromBuffer(void *const buf, const size_t objsize, const size_t len)
{
ObjPool objpool = { 0 };
// If the object size isn't large enough to align to a size_t, then we can't use it.
if ((buf == NULL) || (len == 0UL) || (objsize < sizeof(size_t)) || (objsize*len != __AlignSize(objsize, sizeof(size_t))*len)) return objpool;
else
{
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
objpool.stack.size = objpool.freeBlocks = len;
objpool.stack.mem = buf;
for (int i = 0; i < objpool.freeBlocks; i++)
{
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
*block.index = i + 1;
}
objpool.stack.base = objpool.stack.mem;
return objpool;
}
}
void DestroyObjPool(ObjPool *const objpool)
{
if ((objpool == NULL) || (objpool->stack.mem == NULL)) return;
else
{
free(objpool->stack.mem);
*objpool = (ObjPool){0};
}
}
void *ObjPoolAlloc(ObjPool *const objpool)
{
if (objpool == NULL) return NULL;
else
{
if (objpool->freeBlocks > 0UL)
{
// For first allocation, head points to the very first index.
// Head = &pool[0];
// ret = Head == ret = &pool[0];
union ObjInfo ret = { .byte = objpool->stack.base };
objpool->freeBlocks--;
// after allocating, we set head to the address of the index that *Head holds.
// Head = &pool[*Head * pool.objsize];
objpool->stack.base = (objpool->freeBlocks != 0UL)? objpool->stack.mem + (*ret.index*objpool->objSize) : NULL;
memset(ret.byte, 0, objpool->objSize);
return ret.byte;
}
else return NULL;
}
}
void ObjPoolFree(ObjPool *const restrict objpool, void *ptr)
{
union ObjInfo p = { .byte = ptr };
if ((objpool == NULL) || (ptr == NULL) || (p.byte < objpool->stack.mem) || (p.byte > objpool->stack.mem + objpool->stack.size*objpool->objSize)) return;
else
{
// When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head.
// *p = index of Head in relation to the buffer;
// Head = p;
*p.index = (objpool->stack.base != NULL)? (objpool->stack.base - objpool->stack.mem)/objpool->objSize : objpool->stack.size;
objpool->stack.base = p.byte;
objpool->freeBlocks++;
}
}
void ObjPoolCleanUp(ObjPool *const restrict objpool, void **ptrref)
{
if ((objpool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return;
else
{
ObjPoolFree(objpool, *ptrref);
*ptrref = NULL;
}
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Double-Ended Stack
//----------------------------------------------------------------------------------
BiStack CreateBiStack(const size_t len)
{
BiStack destack = { 0 };
if (len == 0UL) return destack;
destack.size = len;
destack.mem = malloc(len*sizeof *destack.mem);
if (destack.mem==NULL) destack.size = 0UL;
else
{
destack.front = destack.mem;
destack.back = destack.mem + len;
}
return destack;
}
BiStack CreateBiStackFromBuffer(void *const buf, const size_t len)
{
BiStack destack = { 0 };
if (len == 0UL || buf == NULL) return destack;
destack.size = len;
destack.mem = destack.front = buf;
destack.back = destack.mem + len;
return destack;
}
void DestroyBiStack(BiStack *const destack)
{
if ((destack == NULL) || (destack->mem == NULL)) return;
free(destack->mem);
*destack = (BiStack){0};
}
void *BiStackAllocFront(BiStack *const destack, const size_t len)
{
if ((destack == NULL) || (destack->mem == NULL)) return NULL;
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
// front end stack is too high!
if (destack->front + ALIGNED_LEN >= destack->back) return NULL;
uint8_t *ptr = destack->front;
destack->front += ALIGNED_LEN;
return ptr;
}
void *BiStackAllocBack(BiStack *const destack, const size_t len)
{
if ((destack == NULL) || (destack->mem == NULL)) return NULL;
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
// back end stack is too low
if (destack->back - ALIGNED_LEN <= destack->front) return NULL;
destack->back -= ALIGNED_LEN;
return destack->back;
}
void BiStackResetFront(BiStack *const destack)
{
if ((destack == NULL) || (destack->mem == NULL)) return;
destack->front = destack->mem;
}
void BiStackResetBack(BiStack *const destack)
{
if ((destack == NULL) || (destack->mem == NULL)) return;
destack->back = destack->mem + destack->size;
}
void BiStackResetAll(BiStack *const destack)
{
BiStackResetBack(destack);
BiStackResetFront(destack);
}
intptr_t BiStackMargins(const BiStack destack)
{
return destack.back - destack.front;
}
#endif // RMEM_IMPLEMENTATION

View file

@ -14,7 +14,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -42,8 +42,7 @@
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#include <stdlib.h> // Required for: abs(), fabs()
#include <math.h> // Required for: sinf(), cosf(), sqrtf()
#include <math.h> // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
//----------------------------------------------------------------------------------
// Defines and Macros
@ -58,14 +57,12 @@
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static Texture2D texShapes = { 0 };
static Rectangle recTexShapes = { 0 };
// ...
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static float EaseCubicInOut(float t, float b, float c, float d); // Cubic easing
static Texture2D GetShapesTexture(void); // Get texture to draw shapes
//----------------------------------------------------------------------------------
// Module Functions Definition
@ -138,16 +135,16 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 0.0f, 1.0f);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(0.0f, 0.0f);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(0.0f, thick);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(d, thick);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(d, 0.0f);
rlEnd();
rlPopMatrix();
@ -241,16 +238,16 @@ void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x, center.y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
angle += (stepLength*2);
@ -261,16 +258,16 @@ void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x, center.y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x, center.y);
}
rlEnd();
@ -398,7 +395,38 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color)
rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
}
rlEnd();
rlEnd();
}
// Draw ellipse
void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
{
if (rlCheckBufferLimit(3*36)) rlglDraw();
rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(centerX, centerY);
rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV);
}
rlEnd();
}
// Draw ellipse outline
void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
{
if (rlCheckBufferLimit(2*36)) rlglDraw();
rlBegin(RL_LINES);
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV);
}
rlEnd();
}
void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAngle, int endAngle, int segments, Color color)
@ -458,16 +486,16 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAng
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
angle += stepLength;
@ -612,16 +640,16 @@ void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color
rlNormal3f(0.0f, 0.0f, 1.0f);
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(0.0f, 0.0f);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(0.0f, rec.height);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(rec.width, rec.height);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(rec.width, 0.0f);
rlEnd();
rlPopMatrix();
@ -655,19 +683,19 @@ void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3,
// NOTE: Default raylib font character 95 is a white square
rlColor4ub(col1.r, col1.g, col1.b, col1.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(rec.x, rec.y);
rlColor4ub(col2.r, col2.g, col2.b, col2.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(rec.x, rec.y + rec.height);
rlColor4ub(col3.r, col3.g, col3.b, col3.a);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
rlColor4ub(col4.r, col4.g, col4.b, col4.a);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(rec.x + rec.width, rec.y);
rlEnd();
rlPopMatrix();
@ -790,13 +818,13 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
for (int i = 0; i < segments/2; i++)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x, center.y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength*2))*radius, center.y + cosf(DEG2RAD*(angle + stepLength*2))*radius);
angle += (stepLength*2);
}
@ -804,70 +832,70 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
if (segments%2)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x, center.y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*radius, center.y + cosf(DEG2RAD*angle)*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*radius, center.y + cosf(DEG2RAD*(angle + stepLength))*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x, center.y);
}
}
// [2] Upper Rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[0].x, point[0].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[8].x, point[8].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[9].x, point[9].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[1].x, point[1].y);
// [4] Right Rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[2].x, point[2].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[9].x, point[9].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[10].x, point[10].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[3].x, point[3].y);
// [6] Bottom Rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[11].x, point[11].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[5].x, point[5].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[4].x, point[4].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[10].x, point[10].y);
// [8] Left Rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[7].x, point[7].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[6].x, point[6].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[11].x, point[11].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[8].x, point[8].y);
// [9] Middle Rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[8].x, point[8].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[11].x, point[11].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[10].x, point[10].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[9].x, point[9].y);
rlEnd();
@ -1022,13 +1050,13 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int
for (int i = 0; i < segments; i++)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*innerRadius, center.y + cosf(DEG2RAD*angle)*innerRadius);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*angle)*outerRadius, center.y + cosf(DEG2RAD*angle)*outerRadius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*outerRadius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(center.x + sinf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + cosf(DEG2RAD*(angle + stepLength))*innerRadius);
angle += stepLength;
@ -1037,46 +1065,46 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int
// Upper rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[0].x, point[0].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[8].x, point[8].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[9].x, point[9].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[1].x, point[1].y);
// Right rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[2].x, point[2].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[10].x, point[10].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[11].x, point[11].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[3].x, point[3].y);
// Lower rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[13].x, point[13].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[5].x, point[5].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[4].x, point[4].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[12].x, point[12].y);
// Left rectangle
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[15].x, point[15].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[7].x, point[7].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(point[6].x, point[6].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(point[14].x, point[14].y);
rlEnd();
@ -1190,16 +1218,16 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(v1.x, v1.y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(v2.x, v2.y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(v2.x, v2.y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(v3.x, v3.y);
rlEnd();
@ -1247,16 +1275,16 @@ void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
for (int i = 1; i < pointsCount - 1; i++)
{
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(points[0].x, points[0].y);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(points[i].x, points[i].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(points[i + 1].x, points[i + 1].y);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(points[i + 1].x, points[i + 1].y);
}
rlEnd();
@ -1314,17 +1342,17 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(0, 0);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f(GetShapesTextureRec().x/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, (GetShapesTextureRec().y + GetShapesTextureRec().height)/GetShapesTexture().height);
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
centralAngle += 360.0f/(float)sides;
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
rlTexCoord2f((GetShapesTextureRec().x + GetShapesTextureRec().width)/GetShapesTexture().width, GetShapesTextureRec().y/GetShapesTexture().height);
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
}
rlEnd();
@ -1346,11 +1374,29 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
rlPopMatrix();
}
// Define default texture used to draw shapes
void SetShapesTexture(Texture2D texture, Rectangle source)
// Draw a polygon outline of n sides
void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color)
{
texShapes = texture;
recTexShapes = source;
if (sides < 3) sides = 3;
float centralAngle = 0.0f;
if (rlCheckBufferLimit(3*(360/sides))) rlglDraw();
rlPushMatrix();
rlTranslatef(center.x, center.y, 0.0f);
rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
rlBegin(RL_LINES);
for (int i = 0; i < sides; i++)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
centralAngle += 360.0f/(float)sides;
rlVertex2f(sinf(DEG2RAD*centralAngle)*radius, cosf(DEG2RAD*centralAngle)*radius);
}
rlEnd();
rlPopMatrix();
}
//----------------------------------------------------------------------------------
@ -1424,8 +1470,8 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
int recCenterX = (int)(rec.x + rec.width/2.0f);
int recCenterY = (int)(rec.y + rec.height/2.0f);
float dx = (float)fabs(center.x - recCenterX);
float dy = (float)fabs(center.y - recCenterY);
float dx = fabsf(center.x - (float)recCenterX);
float dy = fabsf(center.y - (float)recCenterY);
if (dx > (rec.width/2.0f + radius)) { return false; }
if (dy > (rec.height/2.0f + radius)) { return false; }
@ -1446,8 +1492,8 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
if (CheckCollisionRecs(rec1, rec2))
{
float dxx = (float)fabs(rec1.x - rec2.x);
float dyy = (float)fabs(rec1.y - rec2.y);
float dxx = fabsf(rec1.x - rec2.x);
float dyy = fabsf(rec1.y - rec2.y);
if (rec1.x <= rec2.x)
{
@ -1520,22 +1566,3 @@ static float EaseCubicInOut(float t, float b, float c, float d)
return 0.5f*c*(t*t*t + 2.0f) + b;
}
// Get texture to draw shapes (RAII)
static Texture2D GetShapesTexture(void)
{
if (texShapes.id == 0)
{
#if defined(SUPPORT_FONT_TEXTURE)
texShapes = GetFontDefault().texture; // Use font texture white character
Rectangle rec = GetFontDefault().recs[95];
// NOTE: We setup a 1px padding on char rectangle to avoid texture bleeding on MSAA filtering
recTexShapes = (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 };
#else
texShapes = GetTextureDefault(); // Use default white texture
recTexShapes = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
#endif
}
return texShapes;
}

View file

@ -27,7 +27,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -54,10 +54,10 @@
#endif
#include <stdlib.h> // Required for: malloc(), free()
#include <string.h> // Required for: strlen()
#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 <ctype.h> // Required for: toupper(), tolower()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fgets()
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy(), strcat(), strncat(), sscanf()
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
#include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
#include "utils.h" // Required for: fopen() Android mapping
@ -73,7 +73,7 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal()
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints
@ -127,7 +127,7 @@ extern void LoadFontDefault(void)
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
// 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
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
defaultFont.charsCount = 224; // Number of chars included in our default font
@ -268,7 +268,7 @@ extern void LoadFontDefault(void)
defaultFont.baseSize = (int)defaultFont.recs[0].height;
TraceLog(LOG_INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
TRACELOG(LOG_INFO, "FONT: Default font loaded successfully");
}
// Unload raylib default font
@ -318,7 +318,7 @@ Font LoadFont(const char *fileName)
if (font.texture.id == 0)
{
TraceLog(LOG_WARNING, "[%s] Font could not be loaded, using default font", fileName);
TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
font = GetFontDefault();
}
else SetTextureFilter(font.texture, FILTER_POINT); // By default we set point filter (best performance)
@ -333,11 +333,11 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
{
Font font = { 0 };
#if defined(SUPPORT_FILEFORMAT_TTF)
font.baseSize = fontSize;
font.charsCount = (charsCount > 0)? charsCount : 95;
font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT);
#if defined(SUPPORT_FILEFORMAT_TTF)
if (font.chars != NULL)
{
Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, 2, 0);
@ -354,7 +354,6 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
}
else font = GetFontDefault();
#else
UnloadFont(font);
font = GetFontDefault();
#endif
@ -435,8 +434,6 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
xPosToRead = charSpacing;
}
TraceLog(LOG_DEBUG, "Font data parsed correctly from image");
// NOTE: We need to remove key color borders from image to avoid weird
// artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR
for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
@ -447,39 +444,37 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
RL_FREE(pixels); // Free pixels array memory
// Create spritefont with all data parsed from image
Font spriteFont = { 0 };
Font font = { 0 };
spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
spriteFont.charsCount = index;
font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
font.charsCount = index;
// We got tempCharValues and tempCharsRecs populated with chars data
// Now we move temp data to sized charValues and charRecs arrays
spriteFont.chars = (CharInfo *)RL_MALLOC(spriteFont.charsCount*sizeof(CharInfo));
spriteFont.recs = (Rectangle *)RL_MALLOC(spriteFont.charsCount*sizeof(Rectangle));
font.chars = (CharInfo *)RL_MALLOC(font.charsCount*sizeof(CharInfo));
font.recs = (Rectangle *)RL_MALLOC(font.charsCount*sizeof(Rectangle));
for (int i = 0; i < spriteFont.charsCount; i++)
for (int i = 0; i < font.charsCount; i++)
{
spriteFont.chars[i].value = tempCharValues[i];
font.chars[i].value = tempCharValues[i];
// Get character rectangle in the font atlas texture
spriteFont.recs[i] = tempCharRecs[i];
font.recs[i] = tempCharRecs[i];
// 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;
font.chars[i].offsetX = 0;
font.chars[i].offsetY = 0;
font.chars[i].advanceX = 0;
// Fill character image data from fontClear data
spriteFont.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
font.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
}
UnloadImage(fontClear); // Unload processed image once converted to texture
spriteFont.baseSize = (int)spriteFont.recs[0].height;
font.baseSize = (int)font.recs[0].height;
TraceLog(LOG_INFO, "Image file loaded correctly as Font");
return spriteFont;
return font;
}
// Load font data for further use
@ -498,100 +493,101 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
#if defined(SUPPORT_FILEFORMAT_TTF)
// Load font data (including pixel data) from TTF file
// NOTE: Loaded information should be enough to generate font image atlas,
// using any packaging method
FILE *fontFile = fopen(fileName, "rb"); // Load font file
// NOTE: Loaded information should be enough to generate
// font image atlas, using any packaging method
unsigned int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
if (fontFile != NULL)
if (fileData != NULL)
{
fseek(fontFile, 0, SEEK_END);
long size = ftell(fontFile); // Get file size
fseek(fontFile, 0, SEEK_SET); // Reset file pointer
unsigned char *fontBuffer = (unsigned char *)RL_MALLOC(size);
fread(fontBuffer, size, 1, fontFile);
fclose(fontFile);
// Init font for data reading
stbtt_fontinfo fontInfo;
if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TraceLog(LOG_WARNING, "Failed to init font!");
// Calculate font scale factor
float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
// Calculate font basic metrics
// NOTE: ascent is equivalent to font baseline
int ascent, descent, lineGap;
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
// In case no chars count provided, default to 95
charsCount = (charsCount > 0)? charsCount : 95;
// Fill fontChars in case not provided externally
// NOTE: By default we fill charsCount consecutevely, starting at 32 (Space)
int genFontChars = false;
if (fontChars == NULL)
stbtt_fontinfo fontInfo = { 0 };
if (stbtt_InitFont(&fontInfo, fileData, 0)) // Init font for data reading
{
fontChars = (int *)RL_MALLOC(charsCount*sizeof(int));
for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32;
genFontChars = true;
}
// Calculate font scale factor
float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo));
// Calculate font basic metrics
// NOTE: ascent is equivalent to font baseline
int ascent, descent, lineGap;
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
// NOTE: Using simple packaging, one char after another
for (int i = 0; i < charsCount; i++)
{
int chw = 0, chh = 0; // Character width and height (on generation)
int ch = fontChars[i]; // Character value to get info for
chars[i].value = ch;
// In case no chars count provided, default to 95
charsCount = (charsCount > 0)? charsCount : 95;
// Render a unicode codepoint to a bitmap
// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
// Fill fontChars in case not provided externally
// NOTE: By default we fill charsCount consecutevely, starting at 32 (Space)
if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else chars[i].image.data = NULL;
if (type == FONT_BITMAP)
if (fontChars == NULL)
{
// Aliased bitmap (black & white) font generation, avoiding anti-aliasing
// NOTE: For optimum results, bitmap font should be generated at base pixel size
for (int p = 0; p < chw*chh; p++)
{
if (((unsigned char *)chars[i].image.data)[p] < BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
else ((unsigned char *)chars[i].image.data)[p] = 255;
}
fontChars = (int *)RL_MALLOC(charsCount*sizeof(int));
for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32;
genFontChars = true;
}
// Load characters images
chars[i].image.width = chw;
chars[i].image.height = chh;
chars[i].image.mipmaps = 1;
chars[i].image.format = UNCOMPRESSED_GRAYSCALE;
chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo));
chars[i].offsetY += (int)((float)ascent*scaleFactor);
// NOTE: Using simple packaging, one char after another
for (int i = 0; i < charsCount; i++)
{
int chw = 0, chh = 0; // Character width and height (on generation)
int ch = fontChars[i]; // Character value to get info for
chars[i].value = ch;
// Get bounding box for character (may be offset to account for chars that dip above or below the line)
int chX1, chY1, chX2, chY2;
stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);
// Render a unicode codepoint to a bitmap
// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
TraceLog(LOG_DEBUG, "Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1);
TraceLog(LOG_DEBUG, "Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1);
if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else chars[i].image.data = NULL;
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
chars[i].advanceX *= scaleFactor;
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);
// Load characters images
chars[i].image.width = chw;
chars[i].image.height = chh;
chars[i].image.mipmaps = 1;
chars[i].image.format = UNCOMPRESSED_GRAYSCALE;
chars[i].offsetY += (int)((float)ascent*scaleFactor);
// NOTE: We create an empty image for space character, it could be further required for atlas packing
if (ch == 32)
{
chars[i].image = GenImageColor(chars[i].advanceX, fontSize, BLANK);
ImageFormat(&chars[i].image, UNCOMPRESSED_GRAYSCALE);
}
if (type == FONT_BITMAP)
{
// Aliased bitmap (black & white) font generation, avoiding anti-aliasing
// NOTE: For optimum results, bitmap font should be generated at base pixel size
for (int p = 0; p < chw*chh; p++)
{
if (((unsigned char *)chars[i].image.data)[p] < BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
else ((unsigned char *)chars[i].image.data)[p] = 255;
}
}
// Get bounding box for character (may be offset to account for chars that dip above or below the line)
/*
int chX1, chY1, chX2, chY2;
stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);
TRACELOGD("FONT: Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1);
TRACELOGD("FONT: Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1);
*/
}
}
else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data");
RL_FREE(fontBuffer);
RL_FREE(fileData);
if (genFontChars) RL_FREE(fontChars);
}
else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName);
#else
TraceLog(LOG_WARNING, "[%s] TTF support is disabled", fileName);
#endif
return chars;
@ -671,8 +667,6 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
}
else if (packMethod == 1) // Use Skyline rect packing algorythm (stb_pack_rect)
{
TraceLog(LOG_DEBUG, "Using Skyline packing algorythm!");
stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context));
stbrp_node *nodes = (stbrp_node *)RL_MALLOC(charsCount*sizeof(*nodes));
@ -709,7 +703,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
}
}
}
else TraceLog(LOG_WARNING, "Character could not be packed: %i", i);
else TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", i);
}
RL_FREE(rects);
@ -742,7 +736,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
// Unload Font from GPU memory (VRAM)
void UnloadFont(Font font)
{
// NOTE: Make sure spriteFont is not default font (fallback)
// NOTE: Make sure font is not default font (fallback)
if (font.texture.id != GetFontDefault().texture.id)
{
for (int i = 0; i < font.charsCount; i++) UnloadImage(font.chars[i].image);
@ -751,7 +745,7 @@ void UnloadFont(Font font)
RL_FREE(font.chars);
RL_FREE(font.recs);
TraceLog(LOG_DEBUG, "Unloaded sprite font data");
TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
}
}
@ -759,22 +753,7 @@ void UnloadFont(Font font)
// NOTE: Uses default font
void DrawFPS(int posX, int posY)
{
// NOTE: We are rendering fps every second for better viewing on high framerates
static int fps = 0;
static int counter = 0;
static int refreshRate = 20;
if (counter < refreshRate) counter++;
else
{
fps = GetFPS();
refreshRate = fps;
counter = 0;
}
// NOTE: We have rounding errors every frame, so it oscillates a lot
DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, LIME);
DrawText(TextFormat("%2i FPS", GetFPS()), posX, posY, 20, LIME);
}
// Draw text (using default font)
@ -795,51 +774,66 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
}
}
// Draw one character (codepoint)
void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float scale, Color tint)
{
// Character index position in sprite font
// NOTE: In case a codepoint is not available in the font, index returned points to '?'
int index = GetGlyphIndex(font, codepoint);
// Character rectangle on screen
// NOTE: Quad is scaled proportionally to base character width-height
Rectangle rec = { position.x, position.y, font.recs[index].width*scale, font.recs[index].height*scale };
DrawTexturePro(font.texture, font.recs[index], rec, (Vector2){ 0, 0 }, 0.0f, tint);
}
// Draw text using Font
// NOTE: chars spacing is NOT proportional to fontSize
void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
{
int length = strlen(text);
int textOffsetY = 0; // Required for line break!
float textOffsetX = 0.0f; // Offset between characters
float scaleFactor = 0.0f;
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
int letter = 0; // Current character
int index = 0; // Index position in sprite font
int textOffsetY = 0; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw
scaleFactor = fontSize/font.baseSize;
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
for (int i = 0; i < length; i++)
{
int next = 0;
letter = GetNextCodepoint(&text[i], &next);
index = GetGlyphIndex(font, letter);
// Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0;
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set 'next = 1'
if (letter == 0x3f) next = 1;
i += (next - 1);
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1;
if (letter == '\n')
if (codepoint == '\n')
{
// NOTE: Fixed line spacing of 1.5 lines
// NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
textOffsetX = 0.0f;
}
else
{
if (letter != ' ')
if ((codepoint != ' ') && (codepoint != '\t'))
{
DrawTexturePro(font.texture, font.recs[index],
(Rectangle){ position.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
position.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.recs[index].width*scaleFactor,
font.recs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
Rectangle rec = { position.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
position.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.recs[index].width*scaleFactor,
font.recs[index].height*scaleFactor };
DrawTexturePro(font.texture, font.recs[index], rec, (Vector2){ 0, 0 }, 0.0f, tint);
}
if (font.chars[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing);
}
i += (codepointByteCount - 1); // Move text bytes counter to next codepoint
}
}
@ -850,37 +844,37 @@ void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, flo
}
// Draw text using font inside rectangle limits with support for text selection
void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectText, Color selectBack)
void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint)
{
int length = strlen(text);
int textOffsetX = 0; // Offset between characters
int textOffsetY = 0; // Required for line break!
float scaleFactor = 0.0f;
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
int letter = 0; // Current character
int index = 0; // Index position in sprite font
int textOffsetY = 0; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw
scaleFactor = fontSize/font.baseSize;
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
// Word/character wrapping mechanism variables
enum { MEASURE_STATE = 0, DRAW_STATE = 1 };
int state = wordWrap? MEASURE_STATE : DRAW_STATE;
int startLine = -1; // Index where to begin drawing (where a line begins)
int endLine = -1; // Index where to stop drawing (where a line ends)
int lastk = -1; // Holds last value of the character position
for (int i = 0, k = 0; i < length; i++, k++)
{
// Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0;
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1;
i += (codepointByteCount - 1);
int glyphWidth = 0;
int next = 0;
letter = GetNextCodepoint(&text[i], &next);
index = GetGlyphIndex(font, letter);
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
if (letter == 0x3f) next = 1;
i += next - 1;
if (letter != '\n')
if (codepoint != '\n')
{
glyphWidth = (font.chars[index].advanceX == 0)?
(int)(font.recs[index].width*scaleFactor + spacing):
@ -894,26 +888,25 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
// and begin drawing on the next line before we can get outside the container.
if (state == MEASURE_STATE)
{
// TODO: there are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
// See: http://jkorpela.fi/chars/spaces.html
if ((letter == ' ') || (letter == '\t') || (letter == '\n')) endLine = i;
// TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
// Ref: http://jkorpela.fi/chars/spaces.html
if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;
if ((textOffsetX + glyphWidth + 1) >= rec.width)
{
endLine = (endLine < 1)? i : endLine;
if (i == endLine) endLine -= next;
if ((startLine + next) == endLine) endLine = i - next;
if (i == endLine) endLine -= codepointByteCount;
if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);
state = !state;
}
else if ((i + 1) == length)
{
endLine = i;
state = !state;
}
else if (letter == '\n')
{
state = !state;
}
else if (codepoint == '\n') state = !state;
if (state == DRAW_STATE)
{
@ -929,7 +922,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
}
else
{
if (letter == '\n')
if (codepoint == '\n')
{
if (!wordWrap)
{
@ -945,26 +938,25 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
textOffsetX = 0;
}
// When text overflows rectangle height limit, just stop drawing
if ((textOffsetY + (int)(font.baseSize*scaleFactor)) > rec.height) break;
// Draw selected
// Draw selection background
bool isGlyphSelected = false;
if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
{
Rectangle strec = {rec.x + textOffsetX-1, rec.y + textOffsetY, glyphWidth, font.baseSize*scaleFactor };
DrawRectangleRec(strec, selectBack);
DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (int)((float)font.baseSize*scaleFactor) }, selectBackTint);
isGlyphSelected = true;
}
// Draw glyph
if ((letter != ' ') && (letter != '\t'))
// Draw current chracter glyph
if ((codepoint != ' ') && (codepoint != '\t'))
{
DrawTexturePro(font.texture, font.recs[index],
(Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.recs[index].width*scaleFactor,
font.recs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f,
(!isGlyphSelected)? tint : selectText);
(Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.recs[index].width*scaleFactor, font.recs[index].height*scaleFactor },
(Vector2){ 0, 0 }, 0.0f, (!isGlyphSelected)? tint : selectTint);
}
}
@ -975,7 +967,9 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
startLine = endLine;
endLine = -1;
glyphWidth = 0;
selectStart += lastk - k;
k = lastk;
state = !state;
}
}
@ -1005,7 +999,7 @@ int MeasureText(const char *text, int fontSize)
// Measure string size for Font
Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
{
int len = strlen(text);
int len = TextLength(text);
int tempLen = 0; // Used to count longer text line num chars
int lenCounter = 0;
@ -1057,15 +1051,17 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
}
// Returns index position for a unicode character on spritefont
int GetGlyphIndex(Font font, int character)
int GetGlyphIndex(Font font, int codepoint)
{
#define TEXT_CHARACTER_NOTFOUND 63 // Character: '?'
#define UNORDERED_CHARSET
#if defined(UNORDERED_CHARSET)
int index = 0;
int index = TEXT_CHARACTER_NOTFOUND;
for (int i = 0; i < font.charsCount; i++)
{
if (font.chars[i].value == character)
if (font.chars[i].value == codepoint)
{
index = i;
break;
@ -1074,12 +1070,36 @@ int GetGlyphIndex(Font font, int character)
return index;
#else
return (character - 32);
return (codepoint - 32);
#endif
}
//----------------------------------------------------------------------------------
// Text strings management functions
//----------------------------------------------------------------------------------
// Copy one string to another, returns bytes copied
int TextCopy(char *dst, const char *src)
{
int bytes = 0;
if (dst != NULL)
{
while (*src != '\0')
{
*dst = *src;
dst++;
src++;
bytes++;
}
*dst = '\0';
}
return bytes;
}
// Check if two text string are equal
// REQUIRES: strcmp()
bool TextIsEqual(const char *text1, const char *text2)
@ -1094,9 +1114,12 @@ bool TextIsEqual(const char *text1, const char *text2)
// Get text length in bytes, check for \0 character
unsigned int TextLength(const char *text)
{
unsigned int length = 0;
unsigned int length = 0; //strlen(text)
while (*text++) length++;
if (text != NULL)
{
while (*text++) length++;
}
return length;
}
@ -1110,14 +1133,15 @@ const char *TextFormat(const char *text, ...)
// We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
static int index = 0;
char *currentBuffer = buffers[index];
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
va_list args;
va_start(args, text);
vsprintf(currentBuffer, text, args);
va_end(args);
index += 1; // Move to next buffer for next function call
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
@ -1125,12 +1149,11 @@ const char *TextFormat(const char *text, ...)
}
// Get a piece of a text string
// REQUIRES: strlen()
const char *TextSubtext(const char *text, int position, int length)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
int textLength = strlen(text);
int textLength = TextLength(text);
if (position >= textLength)
{
@ -1152,7 +1175,7 @@ const char *TextSubtext(const char *text, int position, int length)
}
// Replace text string
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
// REQUIRES: strstr(), strncpy(), strcpy()
// WARNING: Internally allocated memory must be freed by the user (if return != NULL)
char *TextReplace(char *text, const char *replace, const char *by)
{
@ -1168,18 +1191,18 @@ char *TextReplace(char *text, const char *replace, const char *by)
// Sanity checks and initialization
if (!text || !replace) return NULL;
replaceLen = strlen(replace);
replaceLen = TextLength(replace);
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
if (!by) by = ""; // Replace by nothing if not provided
byLen = strlen(by);
byLen = TextLength(by);
// Count the number of replacements needed
insertPoint = text;
for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
// Allocate returning string and point temp to it
temp = result = RL_MALLOC(strlen(text) + (byLen - replaceLen)*count + 1);
temp = result = RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1);
if (!result) return NULL; // Memory could not be allocated
@ -1203,12 +1226,11 @@ char *TextReplace(char *text, const char *replace, const char *by)
}
// Insert text in a specific position, moves all text forward
// REQUIRES: strlen(), strcpy(), strtok()
// WARNING: Allocated memory should be manually freed
char *TextInsert(const char *text, const char *insert, int position)
{
int textLen = strlen(text);
int insertLen = strlen(insert);
int textLen = TextLength(text);
int insertLen = TextLength(insert);
char *result = (char *)RL_MALLOC(textLen + insertLen + 1);
@ -1229,11 +1251,11 @@ const char *TextJoin(const char **textList, int count, const char *delimiter)
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
int totalLength = 0;
int delimiterLen = strlen(delimiter);
int delimiterLen = TextLength(delimiter);
for (int i = 0; i < count; i++)
{
int textListLength = strlen(textList[i]);
int textListLength = TextLength(textList[i]);
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
if ((totalLength + textListLength) < MAX_TEXT_BUFFER_LENGTH)
@ -1273,7 +1295,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
counter = 1;
// Count how many substrings we have on text and point to every one
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
for (int i = 0; i < TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH; i++)
{
buffer[i] = text[i];
if (buffer[i] == '\0') break;
@ -1297,7 +1319,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
void TextAppend(char *text, const char *append, int *position)
{
strcpy(text + *position, append);
*position += strlen(append);
*position += TextLength(append);
}
// Find first text occurrence within a string
@ -1314,14 +1336,20 @@ int TextFindIndex(const char *text, const char *find)
}
// Get upper case version of provided string
// REQUIRES: toupper()
const char *TextToUpper(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
{
if (text[i] != '\0') buffer[i] = (char)toupper(text[i]);
if (text[i] != '\0')
{
buffer[i] = (char)toupper(text[i]);
//if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
// TODO: Support Utf8 diacritics!
//if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
}
else { buffer[i] = '\0'; break; }
}
@ -1329,14 +1357,17 @@ const char *TextToUpper(const char *text)
}
// Get lower case version of provided string
// REQUIRES: tolower()
const char *TextToLower(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
{
if (text[i] != '\0') buffer[i] = (char)tolower(text[i]);
if (text[i] != '\0')
{
buffer[i] = (char)tolower(text[i]);
//if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
}
else { buffer[i] = '\0'; break; }
}
@ -1344,7 +1375,6 @@ const char *TextToLower(const char *text)
}
// Get Pascal case notation version of provided string
// REQUIRES: toupper()
const char *TextToPascal(const char *text)
{
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
@ -1369,22 +1399,21 @@ const char *TextToPascal(const char *text)
}
// Get integer value from text
// NOTE: Negative values not supported
// NOTE: This function replaces atoi() [stdlib.h]
int TextToInteger(const char *text)
{
int result = 0;
int len = strlen(text);
int units = 1;
int value = 0;
int sign = 1;
for (int i = len - 1; i >= 0; i--)
if ((text[0] == '+') || (text[0] == '-'))
{
if ((text[i] > 47) && (text[i] < 58)) result += ((int)text[i] - 48)*units;
else { result = -1; break; }
units *= 10;
if (text[0] == '-') sign = -1;
text++;
}
return result;
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
return value*sign;
}
// Encode text codepoint into utf8 text (memory must be freed!)
@ -1392,20 +1421,22 @@ char *TextToUtf8(int *codepoints, int length)
{
// We allocate enough memory fo fit all possible codepoints
// NOTE: 5 bytes for every codepoint should be enough
char *text = (char *)calloc(length*5, 1);
char *text = (char *)RL_CALLOC(length*5, 1);
const char *utf8 = NULL;
int size = 0;
for (int i = 0, bytes = 0; i < length; i++)
{
utf8 = CodepointToUtf8(codepoints[i], &bytes);
strncpy(text + size, utf8, bytes);
size += bytes;
}
// Resize memory to text length + string NULL terminator
text = realloc(text, size + 1);
void *ptr = RL_REALLOC(text, size + 1);
if (ptr != NULL) text = (char *)ptr;
return text;
}
@ -1416,7 +1447,7 @@ int *GetCodepoints(const char *text, int *count)
memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int));
int bytesProcessed = 0;
int textLength = strlen(text);
int textLength = TextLength(text);
int codepointsCount = 0;
for (int i = 0; i < textLength; codepointsCount++)
@ -1613,7 +1644,6 @@ static Font LoadBMFont(const char *fileName)
#define MAX_BUFFER_SIZE 256
Font font = { 0 };
font.texture.id = 0;
char buffer[MAX_BUFFER_SIZE] = { 0 };
char *searchPoint = NULL;
@ -1632,7 +1662,7 @@ static Font LoadBMFont(const char *fileName)
if (fntFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] FNT file could not be opened", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open FNT file", fileName);
return font;
}
@ -1645,20 +1675,21 @@ static Font LoadBMFont(const char *fileName)
searchPoint = strstr(buffer, "lineHeight");
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight);
TraceLog(LOG_DEBUG, "[%s] Font size: %i", fileName, fontSize);
TraceLog(LOG_DEBUG, "[%s] Font texture scale: %ix%i", fileName, texWidth, texHeight);
TRACELOGD("FONT: [%s] Loaded font info:", fileName);
TRACELOGD(" > Base size: %i", fontSize);
TRACELOGD(" > Texture scale: %ix%i", texWidth, texHeight);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "file");
sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName);
TraceLog(LOG_DEBUG, "[%s] Font texture filename: %s", fileName, texFileName);
TRACELOGD(" > Texture filename: %s", texFileName);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "count");
sscanf(searchPoint, "count=%i", &charsCount);
TraceLog(LOG_DEBUG, "[%s] Font num chars: %i", fileName, charsCount);
TRACELOGD(" > Chars count: %i", charsCount);
// Compose correct path using route of .fnt file (fileName) and texFileName
char *texPath = NULL;
@ -1671,14 +1702,14 @@ static Font LoadBMFont(const char *fileName)
}
// NOTE: We need some extra space to avoid memory corruption on next allocations!
texPath = RL_MALLOC(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4);
texPath = RL_MALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(texFileName) + 4);
// NOTE: strcat() and strncat() required a '\0' terminated string to work!
*texPath = '\0';
strncat(texPath, fileName, strlen(fileName) - strlen(lastSlash) + 1);
strncat(texPath, texFileName, strlen(texFileName));
strncat(texPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
strncat(texPath, texFileName, TextLength(texFileName));
TraceLog(LOG_DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
TRACELOGD(" > Texture loading path: %s", texPath);
Image imFont = LoadImage(texPath);
@ -1728,8 +1759,9 @@ static Font LoadBMFont(const char *fileName)
{
UnloadFont(font);
font = GetFontDefault();
TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName);
}
else TraceLog(LOG_INFO, "[%s] Font loaded successfully", fileName);
else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully", fileName);
return font;
}

View file

@ -38,7 +38,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2013-2020 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -65,14 +65,15 @@
#endif
#include <stdlib.h> // Required for: malloc(), free()
#include <string.h> // Required for: strlen()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fread()
#include <string.h> // Required for: strlen() [Used in ImageTextEx()]
#include <math.h> // Required for: fabsf()
#include "utils.h" // Required for: fopen() Android mapping
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
// Required for: rlLoadTexture() rlDeleteTextures(),
// rlGenerateMipmaps(), some funcs for DrawTexturePro()
// rlGenerateMipmaps(), some funcs for DrawTexturePro()
// Support only desired texture formats on stb_image
#if !defined(SUPPORT_FILEFORMAT_BMP)
@ -115,7 +116,7 @@
#define STBI_MALLOC RL_MALLOC
#define STBI_FREE RL_FREE
#define STBI_REALLOC(p,newsz) realloc(p,newsz)
#define STBI_REALLOC RL_REALLOC
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h" // Required for: stbi_load_from_file()
@ -123,14 +124,20 @@
#endif
#if defined(SUPPORT_IMAGE_EXPORT)
#define STBIW_MALLOC RL_MALLOC
#define STBIW_FREE RL_FREE
#define STBIW_REALLOC RL_REALLOC
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "external/stb_image_write.h" // Required for: stbi_write_*()
#endif
#if defined(SUPPORT_IMAGE_MANIPULATION)
#define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size))
#define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr))
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8()
// NOTE: Used for image scaling on ImageResize()
#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() [ImageResize()]
#endif
#if defined(SUPPORT_IMAGE_GENERATION)
@ -195,6 +202,7 @@ Image LoadImage(const char *fileName)
defined(SUPPORT_FILEFORMAT_TGA) || \
defined(SUPPORT_FILEFORMAT_GIF) || \
defined(SUPPORT_FILEFORMAT_PIC) || \
defined(SUPPORT_FILEFORMAT_HDR) || \
defined(SUPPORT_FILEFORMAT_PSD)
#define STBI_REQUIRED
#endif
@ -225,53 +233,53 @@ Image LoadImage(const char *fileName)
)
{
#if defined(STBI_REQUIRED)
int imgWidth = 0;
int imgHeight = 0;
int imgBpp = 0;
// NOTE: Using stb_image to load images (Supports multiple image formats)
FILE *imFile = fopen(fileName, "rb");
unsigned int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
if (imFile != NULL)
if (fileData != NULL)
{
// NOTE: Using stb_image to load images (Supports multiple image formats)
image.data = stbi_load_from_file(imFile, &imgWidth, &imgHeight, &imgBpp, 0);
int comp = 0;
image.data = stbi_load_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 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 (comp == 1) image.format = UNCOMPRESSED_GRAYSCALE;
else if (comp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA;
else if (comp == 3) image.format = UNCOMPRESSED_R8G8B8;
else if (comp == 4) image.format = UNCOMPRESSED_R8G8B8A8;
RL_FREE(fileData);
}
#endif
}
#if defined(SUPPORT_FILEFORMAT_HDR)
else if (IsFileExtension(fileName, ".hdr"))
{
int imgBpp = 0;
#if defined(STBI_REQUIRED)
unsigned int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
FILE *imFile = fopen(fileName, "rb");
// Load 32 bit per channel floats data
//stbi_set_flip_vertically_on_load(true);
image.data = stbi_loadf_from_file(imFile, &image.width, &image.height, &imgBpp, 0);
fclose(imFile);
image.mipmaps = 1;
if (imgBpp == 1) image.format = UNCOMPRESSED_R32;
else if (imgBpp == 3) image.format = UNCOMPRESSED_R32G32B32;
else if (imgBpp == 4) image.format = UNCOMPRESSED_R32G32B32A32;
else
if (fileData != NULL)
{
TraceLog(LOG_WARNING, "[%s] Image fileformat not supported", fileName);
UnloadImage(image);
int comp = 0;
image.data = stbi_loadf_from_memory(fileData, dataSize, &image.width, &image.height, &comp, 0);
image.mipmaps = 1;
if (comp == 1) image.format = UNCOMPRESSED_R32;
else if (comp == 3) image.format = UNCOMPRESSED_R32G32B32;
else if (comp == 4) image.format = UNCOMPRESSED_R32G32B32A32;
else
{
TRACELOG(LOG_WARNING, "IMAGE: [%s] HDR fileformat not supported", fileName);
UnloadImage(image);
}
RL_FREE(fileData);
}
#endif
}
#endif
#if defined(SUPPORT_FILEFORMAT_DDS)
@ -289,10 +297,10 @@ Image LoadImage(const char *fileName)
#if defined(SUPPORT_FILEFORMAT_ASTC)
else if (IsFileExtension(fileName, ".astc")) image = LoadASTC(fileName);
#endif
else TraceLog(LOG_WARNING, "[%s] Image fileformat not supported", fileName);
else TRACELOG(LOG_WARNING, "IMAGE: [%s] Fileformat not supported", fileName);
if (image.data != NULL) TraceLog(LOG_INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height);
else TraceLog(LOG_WARNING, "[%s] Image could not be loaded", fileName);
if (image.data != NULL) TRACELOG(LOG_INFO, "IMAGE: [%s] Data loaded successfully (%ix%i)", fileName, image.width, image.height);
else TRACELOG(LOG_WARNING, "IMAGE: [%s] Failed to load data", fileName);
return image;
}
@ -301,7 +309,7 @@ Image LoadImage(const char *fileName)
// NOTE: Creates a copy of pixels data array
Image LoadImageEx(Color *pixels, int width, int height)
{
Image image;
Image image = { 0 };
image.data = NULL;
image.width = width;
image.height = height;
@ -346,40 +354,24 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
{
Image image = { 0 };
FILE *rawFile = fopen(fileName, "rb");
unsigned int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
if (rawFile == NULL)
if (fileData != NULL)
{
TraceLog(LOG_WARNING, "[%s] RAW image file could not be opened", fileName);
}
else
{
if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET);
unsigned char *dataPtr = fileData;
unsigned int size = GetPixelDataSize(width, height, format);
if (headerSize > 0) dataPtr += headerSize;
image.data = RL_MALLOC(size); // Allocate required memory in bytes
memcpy(image.data, dataPtr, size); // Copy required data to image
image.width = width;
image.height = height;
image.mipmaps = 1;
image.format = format;
// NOTE: fread() returns num read elements instead of bytes,
// to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element)
int bytes = fread(image.data, 1, size, rawFile);
// Check if data has been read successfully
if (bytes < size)
{
TraceLog(LOG_WARNING, "[%s] RAW image data can not be read, wrong requested format or size", fileName);
RL_FREE(image.data);
}
else
{
image.width = width;
image.height = height;
image.mipmaps = 1;
image.format = format;
}
fclose(rawFile);
RL_FREE(fileData);
}
return image;
@ -397,7 +389,6 @@ Texture2D LoadTexture(const char *fileName)
texture = LoadTextureFromImage(image);
UnloadImage(image);
}
else TraceLog(LOG_WARNING, "Texture could not be created");
return texture;
}
@ -412,7 +403,7 @@ Texture2D LoadTextureFromImage(Image image)
{
texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
}
else TraceLog(LOG_WARNING, "Texture could not be loaded from Image");
else TRACELOG(LOG_WARNING, "IMAGE: Data is not valid to load texture");
texture.width = image.width;
texture.height = image.height;
@ -444,7 +435,7 @@ void UnloadTexture(Texture2D texture)
{
rlDeleteTextures(texture.id);
TraceLog(LOG_INFO, "[TEX ID %i] Unloaded texture data from VRAM (GPU)", texture.id);
TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Unloaded texture data from VRAM (GPU)", texture.id);
}
}
@ -457,16 +448,16 @@ void UnloadRenderTexture(RenderTexture2D target)
// Get pixel data from image in the form of Color struct array
Color *GetImageData(Image image)
{
if ((image.width == 0) || (image.height == 0)) return NULL;
Color *pixels = (Color *)RL_MALLOC(image.width*image.height*sizeof(Color));
if (pixels == NULL) return pixels;
if (image.format >= COMPRESSED_DXT1_RGB) TraceLog(LOG_WARNING, "Pixel data retrieval not supported for compressed image formats");
if (image.format >= COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
else
{
if ((image.format == UNCOMPRESSED_R32) ||
(image.format == UNCOMPRESSED_R32G32B32) ||
(image.format == UNCOMPRESSED_R32G32B32A32)) TraceLog(LOG_WARNING, "32bit pixel format converted to 8bit per channel");
(image.format == UNCOMPRESSED_R32G32B32A32)) TRACELOG(LOG_WARNING, "IMAGE: Pixel format converted from 32bit to 8bit per channel");
for (int i = 0, k = 0; i < image.width*image.height; i++)
{
@ -576,7 +567,7 @@ Vector4 *GetImageDataNormalized(Image image)
{
Vector4 *pixels = (Vector4 *)RL_MALLOC(image.width*image.height*sizeof(Vector4));
if (image.format >= COMPRESSED_DXT1_RGB) TraceLog(LOG_WARNING, "Pixel data retrieval not supported for compressed image formats");
if (image.format >= COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Pixel data retrieval not supported for compressed image formats");
else
{
for (int i = 0, k = 0; i < image.width*image.height; i++)
@ -686,9 +677,9 @@ Vector4 *GetImageDataNormalized(Image image)
Rectangle GetImageAlphaBorder(Image image, float threshold)
{
Rectangle crop = { 0 };
Color *pixels = GetImageData(image);
if (pixels != NULL)
{
int xMin = 65536; // Define a big enough number
@ -710,7 +701,11 @@ Rectangle GetImageAlphaBorder(Image image, float threshold)
}
}
crop = (Rectangle){ xMin, yMin, (xMax + 1) - xMin, (yMax + 1) - yMin };
// Check for empty blank image
if ((xMin != 65536) && (xMax != 65536))
{
crop = (Rectangle){ xMin, yMin, (xMax + 1) - xMin, (yMax + 1) - yMin };
}
RL_FREE(pixels);
}
@ -773,16 +768,17 @@ Image GetTextureData(Texture2D texture)
image.format = texture.format;
image.mipmaps = 1;
// NOTE: Data retrieved on OpenGL ES 2.0 should be RGBA
// coming from FBO color buffer, but it seems original
// texture format is retrieved on RPI... weird...
//image.format = UNCOMPRESSED_R8G8B8A8;
TraceLog(LOG_INFO, "Texture pixel data obtained successfully");
#if defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: Data retrieved on OpenGL ES 2.0 should be RGBA,
// coming from FBO color buffer attachment, but it seems
// original texture format is retrieved on RPI...
image.format = UNCOMPRESSED_R8G8B8A8;
#endif
TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Pixel data retrieved successfully", texture.id);
}
else TraceLog(LOG_WARNING, "Texture pixel data could not be obtained");
else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve pixel data", texture.id);
}
else TraceLog(LOG_WARNING, "Compressed texture data could not be obtained");
else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve compressed pixel data", texture.id);
return image;
}
@ -839,16 +835,15 @@ void ExportImage(Image image, const char *fileName)
{
// Export raw pixel data (without header)
// NOTE: It's up to the user to track image parameters
FILE *rawFile = fopen(fileName, "wb");
success = fwrite(image.data, GetPixelDataSize(image.width, image.height, image.format), 1, rawFile);
fclose(rawFile);
SaveFileData(fileName, image.data, GetPixelDataSize(image.width, image.height, image.format));
success = true;
}
RL_FREE(imgData);
#endif
if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName);
else TraceLog(LOG_WARNING, "Image could not be exported.");
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image exported successfully", fileName);
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image", fileName);
}
// Export image as code file (.h) defining an array of bytes
@ -870,7 +865,7 @@ void ExportImageAsCode(Image image, const char *fileName)
fprintf(txtFile, "// more info and bugs-report: github.com/raysan5/raylib //\n");
fprintf(txtFile, "// feedback and support: ray[at]raylib.com //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "// Copyright (c) 2019 Ramon Santamaria (@raysan5) //\n");
fprintf(txtFile, "// Copyright (c) 2020 Ramon Santamaria (@raysan5) //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
@ -948,8 +943,6 @@ void ImageToPOT(Image *image, Color fillColor)
// Security check to avoid program crash
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
Color *pixels = GetImageData(*image); // Get pixels data
// Calculate next power-of-two values
// NOTE: Just add the required amount of pixels at the right and bottom sides of image...
int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
@ -958,6 +951,7 @@ void ImageToPOT(Image *image, Color fillColor)
// Check if POT texture generation is required (if texture is not already POT)
if ((potWidth != image->width) || (potHeight != image->height))
{
Color *pixels = GetImageData(*image); // Get pixels data
Color *pixelsPOT = NULL;
// Generate POT array from NPOT data
@ -972,19 +966,20 @@ void ImageToPOT(Image *image, Color fillColor)
}
}
TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight);
RL_FREE(pixels); // Free pixels data
RL_FREE(image->data); // Free old image data
RL_FREE(pixels); // Free pixels data
RL_FREE(image->data); // Free old image data
int format = image->format; // Store image data format to reconvert later
// NOTE: Image size changes, new width and height
*image = LoadImageEx(pixelsPOT, potWidth, potHeight);
RL_FREE(pixelsPOT); // Free POT pixels data
RL_FREE(pixelsPOT); // Free POT pixels data
ImageFormat(image, format); // Reconvert image to previous format
ImageFormat(image, format); // Reconvert image to previous format
// TODO: Verification required for log
TRACELOG(LOG_WARNING, "IMAGE: Converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight);
}
}
@ -1162,7 +1157,7 @@ void ImageFormat(Image *image, int newFormat)
#endif
}
}
else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted");
else TRACELOG(LOG_WARNING, "IMAGE: Data format is compressed, can not be converted");
}
}
@ -1173,11 +1168,11 @@ void ImageAlphaMask(Image *image, Image alphaMask)
{
if ((image->width != alphaMask.width) || (image->height != alphaMask.height))
{
TraceLog(LOG_WARNING, "Alpha mask must be same size as image");
TRACELOG(LOG_WARNING, "IMAGE: Alpha mask must be same size as image");
}
else if (image->format >= COMPRESSED_DXT1_RGB)
{
TraceLog(LOG_WARNING, "Alpha mask can not be applied to compressed data formats");
TRACELOG(LOG_WARNING, "IMAGE: Alpha mask can not be applied to compressed data formats");
}
else
{
@ -1234,6 +1229,7 @@ void ImageAlphaClear(Image *image, Color color, float threshold)
*image = LoadImageEx(pixels, image->width, image->height);
ImageFormat(image, prevFormat);
RL_FREE(pixels);
}
// Premultiply alpha channel
@ -1259,6 +1255,7 @@ void ImageAlphaPremultiply(Image *image)
*image = LoadImageEx(pixels, image->width, image->height);
ImageFormat(image, prevFormat);
RL_FREE(pixels);
}
#if defined(SUPPORT_IMAGE_MANIPULATION)
@ -1335,11 +1332,11 @@ TextureCubemap LoadTextureCubemap(Image image, int layoutType)
for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, size*i, size, size }, WHITE);
cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
if (cubemap.id == 0) TraceLog(LOG_WARNING, "Cubemap image could not be loaded.");
if (cubemap.id == 0) TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
UnloadImage(faces);
}
else TraceLog(LOG_WARNING, "Cubemap image layout can not be detected.");
else TRACELOG(LOG_WARNING, "IMAGE: Failed to detect cubemap image layout");
return cubemap;
}
@ -1384,7 +1381,7 @@ void ImageCrop(Image *image, Rectangle crop)
// Reformat 32bit RGBA image to original format
ImageFormat(image, format);
}
else TraceLog(LOG_WARNING, "Image can not be cropped, crop rectangle out of bounds");
else TRACELOG(LOG_WARNING, "IMAGE: Failed to crop, rectangle out of bounds");
}
// Crop image depending on alpha value
@ -1587,26 +1584,18 @@ void ImageMipmaps(Image *image)
if (mipWidth < 1) mipWidth = 1;
if (mipHeight < 1) mipHeight = 1;
TraceLog(LOG_DEBUG, "Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize);
TRACELOGD("IMAGE: Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize);
mipCount++;
mipSize += GetPixelDataSize(mipWidth, mipHeight, image->format); // Add mipmap size (in bytes)
}
TraceLog(LOG_DEBUG, "Mipmaps available: %i - Mipmaps required: %i", image->mipmaps, mipCount);
TraceLog(LOG_DEBUG, "Mipmaps total size required: %i", mipSize);
TraceLog(LOG_DEBUG, "Image data memory start address: 0x%x", image->data);
if (image->mipmaps < mipCount)
{
void *temp = realloc(image->data, mipSize);
void *temp = RL_REALLOC(image->data, mipSize);
if (temp != NULL)
{
image->data = temp; // Assign new pointer (new size) to store mipmaps data
TraceLog(LOG_DEBUG, "Image data memory point reallocated: 0x%x", temp);
}
else TraceLog(LOG_WARNING, "Mipmaps required memory could not be allocated");
if (temp != NULL) image->data = temp; // Assign new pointer (new size) to store mipmaps data
else TRACELOG(LOG_WARNING, "IMAGE: Mipmaps required memory could not be allocated");
// Pointer to allocated memory point where store next mipmap level data
unsigned char *nextmip = (unsigned char *)image->data + GetPixelDataSize(image->width, image->height, image->format);
@ -1618,7 +1607,7 @@ void ImageMipmaps(Image *image)
for (int i = 1; i < mipCount; i++)
{
TraceLog(LOG_DEBUG, "Gen mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip);
TRACELOGD("IMAGE: Generating mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip);
ImageResize(&imCopy, mipWidth, mipHeight); // Uses internally Mitchell cubic downscale filter
@ -1638,7 +1627,7 @@ void ImageMipmaps(Image *image)
UnloadImage(imCopy);
}
else TraceLog(LOG_WARNING, "Image mipmaps already available");
else TRACELOG(LOG_WARNING, "IMAGE: Mipmaps already available");
}
// Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
@ -1651,13 +1640,13 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
if (image->format >= COMPRESSED_DXT1_RGB)
{
TraceLog(LOG_WARNING, "Compressed data formats can not be dithered");
TRACELOG(LOG_WARNING, "IMAGE: Compressed data formats can not be dithered");
return;
}
if ((rBpp + gBpp + bBpp + aBpp) > 16)
{
TraceLog(LOG_WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
TRACELOG(LOG_WARNING, "IMAGE: Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp));
}
else
{
@ -1667,7 +1656,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8))
{
TraceLog(LOG_WARNING, "Image format is already 16bpp or lower, dithering could have no effect");
TRACELOG(LOG_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
@ -1677,7 +1666,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
else
{
image->format = 0;
TraceLog(LOG_WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp);
TRACELOG(LOG_WARNING, "IMAGE: 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)
@ -1791,7 +1780,7 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount)
if (palCount >= maxPaletteSize)
{
i = image.width*image.height; // Finish palette get
TraceLog(LOG_WARNING, "Image palette is greater than %i colors!", maxPaletteSize);
TRACELOG(LOG_WARNING, "IMAGE: Palette is greater than %i colors", maxPaletteSize);
}
}
}
@ -1820,13 +1809,13 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
if ((srcRec.x + srcRec.width) > src.width)
{
srcRec.width = src.width - srcRec.x;
TraceLog(LOG_WARNING, "Source rectangle width out of bounds, rescaled width: %i", srcRec.width);
TRACELOG(LOG_WARNING, "IMAGE: Source rectangle width out of bounds, rescaled width: %i", srcRec.width);
}
if ((srcRec.y + srcRec.height) > src.height)
{
srcRec.height = src.height - srcRec.y;
TraceLog(LOG_WARNING, "Source rectangle height out of bounds, rescaled height: %i", srcRec.height);
TRACELOG(LOG_WARNING, "IMAGE: Source rectangle height out of bounds, rescaled height: %i", srcRec.height);
}
Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it
@ -1941,9 +1930,8 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
{
int length = strlen(text);
int index; // Index position in sprite font
int letter = 0; // Current character
int positionX = 0; // Image drawing position
int textOffsetX = 0; // Image drawing position X
int textOffsetY = 0; // Offset between lines (on line break '\n')
// NOTE: Text image is generated at font base size, later scaled to desired font size
Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing);
@ -1953,36 +1941,42 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
for (int i = 0; i < length; i++)
{
int next = 0;
letter = GetNextCodepoint(&text[i], &next);
index = GetGlyphIndex(font, letter);
// Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0;
int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint);
if (letter == 0x3f) next = 1;
i += (next - 1);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1;
if (letter == '\n')
if (codepoint == '\n')
{
// TODO: Support line break
// NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user
textOffsetY += (font.baseSize + font.baseSize/2);
textOffsetX = 0.0f;
}
else
{
if (letter != ' ')
if ((codepoint != ' ') && (codepoint != '\t'))
{
ImageDraw(&imText, font.chars[index].image, (Rectangle){ 0, 0, font.chars[index].image.width, font.chars[index].image.height },
(Rectangle){ (float)(positionX + font.chars[index].offsetX),(float)font.chars[index].offsetY,
font.chars[index].image.width, font.chars[index].image.height }, tint);
Rectangle rec = { textOffsetX + font.chars[index].offsetX, textOffsetY + font.chars[index].offsetY, font.recs[index].width, font.recs[index].height };
ImageDraw(&imText, font.chars[index].image, (Rectangle){ 0, 0, font.chars[index].image.width, font.chars[index].image.height }, rec, tint);
}
if (font.chars[index].advanceX == 0) positionX += (int)(font.recs[index].width + spacing);
else positionX += font.chars[index].advanceX + (int)spacing;
if (font.chars[index].advanceX == 0) textOffsetX += (int)(font.recs[index].width + spacing);
else textOffsetX += font.chars[index].advanceX + (int)spacing;
}
i += (codepointByteCount - 1); // Move text bytes counter to next codepoint
}
// Scale image depending on text size
if (fontSize > imSize.y)
{
float scaleFactor = fontSize/imSize.y;
TraceLog(LOG_INFO, "Image text scaled by factor: %f", scaleFactor);
TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
// Using nearest-neighbor scaling algorithm for default font
if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
@ -1993,7 +1987,19 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
}
// Draw rectangle within an image
void ImageDrawRectangle(Image *dst, Rectangle rec, Color color)
void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color)
{
ImageDrawRectangleRec(dst, (Rectangle){ posX, posY, width, height }, color);
}
// Draw rectangle within an image (Vector version)
void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color)
{
ImageDrawRectangle(dst, position.x, position.y, size.x, size.y, color);
}
// Draw rectangle within an image
void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
{
// Security check to avoid program crash
if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
@ -2006,10 +2012,86 @@ void ImageDrawRectangle(Image *dst, Rectangle rec, Color color)
// Draw rectangle lines within an image
void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color)
{
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y, rec.width, thick }, color);
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y + thick, thick, rec.height - thick*2 }, color);
ImageDrawRectangle(dst, (Rectangle){ rec.x + rec.width - thick, rec.y + thick, thick, rec.height - thick*2 }, color);
ImageDrawRectangle(dst, (Rectangle){ rec.x, rec.y + rec.height - thick, rec.width, thick }, color);
ImageDrawRectangle(dst, rec.x, rec.y, rec.width, thick, color);
ImageDrawRectangle(dst, rec.x, rec.y + thick, thick, rec.height - thick*2, color);
ImageDrawRectangle(dst, rec.x + rec.width - thick, rec.y + thick, thick, rec.height - thick*2, color);
ImageDrawRectangle(dst, rec.x, rec.y + rec.height - thick, rec.width, thick, color);
}
// Clear image background with given color
void ImageClearBackground(Image *dst, Color color)
{
ImageDrawRectangle(dst, 0, 0, dst->width, dst->height, color);
}
// Draw pixel within an image
void ImageDrawPixel(Image *dst, int x, int y, Color color)
{
ImageDrawRectangle(dst, x, y, 1, 1, color);
}
// Draw pixel within an image (Vector version)
void ImageDrawPixelV(Image *dst, Vector2 position, Color color)
{
ImageDrawRectangle(dst, (int)position.x, (int)position.y, 1, 1, color);
}
// Draw circle within an image
void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color)
{
int x = 0, y = radius;
int decesionParameter = 3 - 2*radius;
while (y >= x)
{
ImageDrawPixel(dst, centerX + x, centerY + y, color);
ImageDrawPixel(dst, centerX - x, centerY + y, color);
ImageDrawPixel(dst, centerX + x, centerY - y, color);
ImageDrawPixel(dst, centerX - x, centerY - y, color);
ImageDrawPixel(dst, centerX + y, centerY + x, color);
ImageDrawPixel(dst, centerX - y, centerY + x, color);
ImageDrawPixel(dst, centerX + y, centerY - x, color);
ImageDrawPixel(dst, centerX - y, centerY - x, color);
x++;
if (decesionParameter > 0)
{
y--;
decesionParameter = decesionParameter + 4*(x - y) + 10;
}
else decesionParameter = decesionParameter + 4*x + 6;
}
}
// Draw circle within an image (Vector version)
void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color)
{
ImageDrawCircle(dst, (int)center.x, (int)center.y, radius, color);
}
// Draw line within an image
void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color)
{
int m = 2*(endPosY - startPosY);
int slopeError = m - (startPosY - startPosX);
for (int x = startPosX, y = startPosY; x <= startPosY; x++)
{
ImageDrawPixel(dst, x, y, color);
slopeError += m;
if (slopeError >= 0)
{
y++;
slopeError -= 2*(startPosY - startPosX);
}
}
}
// Draw line within an image (Vector version)
void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color)
{
ImageDrawLine(dst, (int)start.x, (int)start.y, (int)end.x, (int)end.y, color);
}
// Draw text (default font) within an image (destination)
@ -2630,7 +2712,7 @@ void SetTextureFilter(Texture2D texture, int filterMode)
}
else
{
TraceLog(LOG_WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
// RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
@ -2698,7 +2780,7 @@ void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float sc
// Draw a part of a texture (defined by a rectangle)
void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint)
{
Rectangle destRec = { position.x, position.y, (float)fabs(sourceRec.width), (float)fabs(sourceRec.height) };
Rectangle destRec = { position.x, position.y, fabsf(sourceRec.width), fabsf(sourceRec.height) };
Vector2 origin = { 0.0f, 0.0f };
DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint);
@ -2977,30 +3059,18 @@ static Image LoadAnimatedGIF(const char *fileName, int *frames, int **delays)
{
Image image = { 0 };
FILE *gifFile = fopen(fileName, "rb");
unsigned int dataSize = 0;
unsigned char *fileData = LoadFileData(fileName, &dataSize);
if (gifFile == NULL)
if (fileData != NULL)
{
TraceLog(LOG_WARNING, "[%s] Animated GIF file could not be opened", fileName);
}
else
{
fseek(gifFile, 0L, SEEK_END);
int size = ftell(gifFile);
fseek(gifFile, 0L, SEEK_SET);
unsigned char *buffer = (unsigned char *)RL_CALLOC(size, sizeof(char));
fread(buffer, sizeof(char), size, gifFile);
fclose(gifFile); // Close file pointer
int comp = 0;
image.data = stbi_load_gif_from_memory(buffer, size, delays, &image.width, &image.height, frames, &comp, 4);
image.data = stbi_load_gif_from_memory(fileData, dataSize, delays, &image.width, &image.height, frames, &comp, 4);
image.mipmaps = 1;
image.format = UNCOMPRESSED_R8G8B8A8;
free(buffer);
RL_FREE(fileData);
}
return image;
@ -3060,31 +3130,32 @@ static Image LoadDDS(const char *fileName)
if (ddsFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] DDS file could not be opened", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open DDS file", fileName);
}
else
{
// Verify the type of file
char ddsHeaderId[4];
char ddsHeaderId[4] = { 0 };
fread(ddsHeaderId, 4, 1, ddsFile);
if ((ddsHeaderId[0] != 'D') || (ddsHeaderId[1] != 'D') || (ddsHeaderId[2] != 'S') || (ddsHeaderId[3] != ' '))
{
TraceLog(LOG_WARNING, "[%s] DDS file does not seem to be a valid image", fileName);
TRACELOG(LOG_WARNING, "IMAGE: [%s] DDS file not a valid image", fileName);
}
else
{
DDSHeader ddsHeader;
DDSHeader ddsHeader = { 0 };
// Get the image header
fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile);
TraceLog(LOG_DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(DDSHeader));
TraceLog(LOG_DEBUG, "[%s] DDS file pixel format size: %i", fileName, ddsHeader.ddspf.size);
TraceLog(LOG_DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, ddsHeader.ddspf.flags);
TraceLog(LOG_DEBUG, "[%s] DDS file format: 0x%x", fileName, ddsHeader.ddspf.fourCC);
TraceLog(LOG_DEBUG, "[%s] DDS file bit count: 0x%x", fileName, ddsHeader.ddspf.rgbBitCount);
TRACELOGD("IMAGE: [%s] DDS file info:", fileName);
TRACELOGD(" > Header size: %i", fileName, sizeof(DDSHeader));
TRACELOGD(" > Pixel format size: %i", fileName, ddsHeader.ddspf.size);
TRACELOGD(" > Pixel format flags: 0x%x", fileName, ddsHeader.ddspf.flags);
TRACELOGD(" > File format: 0x%x", fileName, ddsHeader.ddspf.fourCC);
TRACELOGD(" > File bit count: 0x%x", fileName, ddsHeader.ddspf.rgbBitCount);
image.width = ddsHeader.width;
image.height = ddsHeader.height;
@ -3139,7 +3210,7 @@ static Image LoadDDS(const char *fileName)
}
}
}
if (ddsHeader.ddspf.flags == 0x40 && ddsHeader.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
else if (ddsHeader.ddspf.flags == 0x40 && ddsHeader.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
{
// NOTE: not sure if this case exists...
image.data = (unsigned char *)RL_MALLOC(image.width*image.height*3*sizeof(unsigned char));
@ -3174,8 +3245,6 @@ static Image LoadDDS(const char *fileName)
if (ddsHeader.mipmapCount > 1) size = ddsHeader.pitchOrLinearSize*2;
else size = ddsHeader.pitchOrLinearSize;
TraceLog(LOG_DEBUG, "Pitch or linear size: %i", ddsHeader.pitchOrLinearSize);
image.data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
fread(image.data, size, 1, ddsFile);
@ -3240,18 +3309,18 @@ static Image LoadPKM(const char *fileName)
if (pkmFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] PKM file could not be opened", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open PKM file", fileName);
}
else
{
PKMHeader pkmHeader;
PKMHeader pkmHeader = { 0 };
// Get the image header
fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile);
if ((pkmHeader.id[0] != 'P') || (pkmHeader.id[1] != 'K') || (pkmHeader.id[2] != 'M') || (pkmHeader.id[3] != ' '))
{
TraceLog(LOG_WARNING, "[%s] PKM file does not seem to be a valid image", fileName);
TRACELOG(LOG_WARNING, "IMAGE: [%s] PKM file not a valid image", fileName);
}
else
{
@ -3260,9 +3329,10 @@ static Image LoadPKM(const char *fileName)
pkmHeader.width = ((pkmHeader.width & 0x00FF) << 8) | ((pkmHeader.width & 0xFF00) >> 8);
pkmHeader.height = ((pkmHeader.height & 0x00FF) << 8) | ((pkmHeader.height & 0xFF00) >> 8);
TraceLog(LOG_DEBUG, "PKM (ETC) image width: %i", pkmHeader.width);
TraceLog(LOG_DEBUG, "PKM (ETC) image height: %i", pkmHeader.height);
TraceLog(LOG_DEBUG, "PKM (ETC) image format: %i", pkmHeader.format);
TRACELOGD("IMAGE: [%s] PKM file info:", fileName);
TRACELOGD(" > Image width: %i", pkmHeader.width);
TRACELOGD(" > Image height: %i", pkmHeader.height);
TRACELOGD(" > Image format: %i", pkmHeader.format);
image.width = pkmHeader.width;
image.height = pkmHeader.height;
@ -3333,11 +3403,11 @@ static Image LoadKTX(const char *fileName)
if (ktxFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] KTX image file could not be opened", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load KTX file", fileName);
}
else
{
KTXHeader ktxHeader;
KTXHeader ktxHeader = { 0 };
// Get the image header
fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
@ -3345,7 +3415,7 @@ static Image LoadKTX(const char *fileName)
if ((ktxHeader.id[1] != 'K') || (ktxHeader.id[2] != 'T') || (ktxHeader.id[3] != 'X') ||
(ktxHeader.id[4] != ' ') || (ktxHeader.id[5] != '1') || (ktxHeader.id[6] != '1'))
{
TraceLog(LOG_WARNING, "[%s] KTX file does not seem to be a valid file", fileName);
TRACELOG(LOG_WARNING, "IMAGE: [%s] KTX file not a valid image", fileName);
}
else
{
@ -3353,9 +3423,10 @@ static Image LoadKTX(const char *fileName)
image.height = ktxHeader.height;
image.mipmaps = ktxHeader.mipmapLevels;
TraceLog(LOG_DEBUG, "KTX (ETC) image width: %i", ktxHeader.width);
TraceLog(LOG_DEBUG, "KTX (ETC) image height: %i", ktxHeader.height);
TraceLog(LOG_DEBUG, "KTX (ETC) image format: 0x%x", ktxHeader.glInternalFormat);
TRACELOGD("IMAGE: [%s] KTX file info:", fileName);
TRACELOGD(" > Image width: %i", ktxHeader.width);
TRACELOGD(" > Image height: %i", ktxHeader.height);
TRACELOGD(" > Image format: 0x%x", ktxHeader.glInternalFormat);
unsigned char unused;
@ -3415,10 +3486,10 @@ static int SaveKTX(Image image, const char *fileName)
FILE *ktxFile = fopen(fileName, "wb");
if (ktxFile == NULL) TraceLog(LOG_WARNING, "[%s] KTX image file could not be created", fileName);
if (ktxFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open KTX file", fileName);
else
{
KTXHeader ktxHeader;
KTXHeader ktxHeader = { 0 };
// KTX identifier (v1.1)
//unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
@ -3447,7 +3518,7 @@ static int SaveKTX(Image image, const char *fileName)
// NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
if (ktxHeader.glFormat == -1) TraceLog(LOG_WARNING, "Image format not supported for KTX export.");
if (ktxHeader.glFormat == -1) TRACELOG(LOG_WARNING, "IMAGE: GL format not supported for KTX export (%i)", ktxHeader.glFormat);
else
{
success = fwrite(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
@ -3542,7 +3613,7 @@ static Image LoadPVR(const char *fileName)
if (pvrFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] PVR file could not be opened", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load PVR file", fileName);
}
else
{
@ -3554,14 +3625,14 @@ static Image LoadPVR(const char *fileName)
// Load different PVR data formats
if (pvrVersion == 0x50)
{
PVRHeaderV3 pvrHeader;
PVRHeaderV3 pvrHeader = { 0 };
// Get PVR image header
fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile);
if ((pvrHeader.id[0] != 'P') || (pvrHeader.id[1] != 'V') || (pvrHeader.id[2] != 'R') || (pvrHeader.id[3] != 3))
{
TraceLog(LOG_WARNING, "[%s] PVR file does not seem to be a valid image", fileName);
TRACELOG(LOG_WARNING, "IMAGE: [%s] PVR file not a valid image", fileName);
}
else
{
@ -3622,7 +3693,7 @@ static Image LoadPVR(const char *fileName)
fread(image.data, dataSize, 1, pvrFile);
}
}
else if (pvrVersion == 52) TraceLog(LOG_INFO, "PVR v2 not supported, update your files to PVR v3");
else if (pvrVersion == 52) TRACELOG(LOG_INFO, "IMAGE: [%s] PVRv2 format not supported, update your files to PVRv3", fileName);
fclose(pvrFile); // Close file pointer
}
@ -3660,18 +3731,18 @@ static Image LoadASTC(const char *fileName)
if (astcFile == NULL)
{
TraceLog(LOG_WARNING, "[%s] ASTC file could not be opened", fileName);
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load ASTC file", fileName);
}
else
{
ASTCHeader astcHeader;
ASTCHeader astcHeader = { 0 };
// Get ASTC image header
fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile);
if ((astcHeader.id[3] != 0x5c) || (astcHeader.id[2] != 0xa1) || (astcHeader.id[1] != 0xab) || (astcHeader.id[0] != 0x13))
{
TraceLog(LOG_WARNING, "[%s] ASTC file does not seem to be a valid image", fileName);
TRACELOG(LOG_WARNING, "IMAGE: [%s] ASTC file not a valid image", fileName);
}
else
{
@ -3679,9 +3750,10 @@ static Image LoadASTC(const char *fileName)
image.width = 0x00000000 | ((int)astcHeader.width[2] << 16) | ((int)astcHeader.width[1] << 8) | ((int)astcHeader.width[0]);
image.height = 0x00000000 | ((int)astcHeader.height[2] << 16) | ((int)astcHeader.height[1] << 8) | ((int)astcHeader.height[0]);
TraceLog(LOG_DEBUG, "ASTC image width: %i", image.width);
TraceLog(LOG_DEBUG, "ASTC image height: %i", image.height);
TraceLog(LOG_DEBUG, "ASTC image blocks: %ix%i", astcHeader.blockX, astcHeader.blockY);
TRACELOGD("IMAGE: [%s] ASTC file info:", fileName);
TRACELOGD(" > Image width: %i", image.width);
TRACELOGD(" > Image height: %i", image.height);
TRACELOGD(" > Image blocks: %ix%i", astcHeader.blockX, astcHeader.blockY);
image.mipmaps = 1; // NOTE: ASTC format only contains one mipmap level
@ -3699,7 +3771,7 @@ static Image LoadASTC(const char *fileName)
if (bpp == 8) image.format = COMPRESSED_ASTC_4x4_RGBA;
else if (bpp == 2) image.format = COMPRESSED_ASTC_8x8_RGBA;
}
else TraceLog(LOG_WARNING, "[%s] ASTC block size configuration not supported", fileName);
else TRACELOG(LOG_WARNING, "IMAGE: [%s] ASTC block size configuration not supported", fileName);
}
fclose(astcFile);

Some files were not shown because too many files have changed in this diff Show more