Merge branch 'raysan5:master' into master
This commit is contained in:
commit
2429fef7b3
49 changed files with 1419 additions and 1195 deletions
|
|
@ -27,6 +27,12 @@ if (${PLATFORM} MATCHES "Desktop")
|
|||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
find_package(OpenGL QUIET)
|
||||
set(LIBS_PRIVATE ${OPENGL_LIBRARIES} winmm)
|
||||
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "QNX")
|
||||
set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
|
||||
find_library(GLESV2 GLESv2)
|
||||
find_library(EGL EGL)
|
||||
set(LIBS_PUBLIC m)
|
||||
set(LIBS_PRIVATE ${GLESV2} ${EGL} atomic pthread dl)
|
||||
elseif (UNIX)
|
||||
find_library(pthread NAMES pthread)
|
||||
find_package(OpenGL QUIET)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ int main(void)
|
|||
.tapbackPos = 0.01f
|
||||
};
|
||||
|
||||
size_t wavCursor = 0;
|
||||
int wavCursor = 0;
|
||||
const short *wavPCM16 = wav.data;
|
||||
|
||||
short chunkSamples[AUDIO_STREAM_RING_BUFFER_SIZE] = { 0 };
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -226,10 +226,10 @@ void UpdateCameraCenterInsideMap(Camera2D *camera, Player *player, EnvItem *envI
|
|||
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera);
|
||||
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera);
|
||||
|
||||
if (max.x < width) camera->offset.x = width - (max.x - width/2);
|
||||
if (max.y < height) camera->offset.y = height - (max.y - height/2);
|
||||
if (min.x > 0) camera->offset.x = width/2 - min.x;
|
||||
if (min.y > 0) camera->offset.y = height/2 - min.y;
|
||||
if (max.x < width) camera->offset.x = width - (max.x - (float)width/2);
|
||||
if (max.y < height) camera->offset.y = height - (max.y - (float)height/2);
|
||||
if (min.x > 0) camera->offset.x = (float)width/2 - min.x;
|
||||
if (min.y > 0) camera->offset.y = (float)height/2 - min.y;
|
||||
}
|
||||
|
||||
void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height)
|
||||
|
|
|
|||
|
|
@ -225,10 +225,10 @@ int main(void)
|
|||
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, camera);
|
||||
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, camera);
|
||||
|
||||
if (max.x < screenWidth) camera.offset.x = screenWidth - (max.x - screenWidth/2);
|
||||
if (max.y < screenHeight) camera.offset.y = screenHeight - (max.y - screenHeight/2);
|
||||
if (min.x > 0) camera.offset.x = screenWidth/2 - min.x;
|
||||
if (min.y > 0) camera.offset.y = screenHeight/2 - min.y;
|
||||
if (max.x < screenWidth) camera.offset.x = screenWidth - (max.x - (float)screenWidth/2);
|
||||
if (max.y < screenHeight) camera.offset.y = screenHeight - (max.y - (float)screenHeight/2);
|
||||
if (min.x > 0) camera.offset.x = (float)screenWidth/2 - min.x;
|
||||
if (min.y > 0) camera.offset.y = (float)screenHeight/2 - min.y;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Events management
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gam
|
|||
|
||||
static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
|
||||
{
|
||||
const float resizeRatio = (float)(screenHeight/gameHeight);
|
||||
const float resizeRatio = (float)screenHeight/gameHeight;
|
||||
sourceRect->x = 0.0f;
|
||||
sourceRect->y = 0.0f;
|
||||
sourceRect->width = (float)(int)(screenWidth/resizeRatio);
|
||||
|
|
@ -230,7 +230,7 @@ static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gam
|
|||
|
||||
static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
|
||||
{
|
||||
const float resizeRatio = (float)(screenWidth/gameWidth);
|
||||
const float resizeRatio = (float)screenWidth/gameWidth;
|
||||
sourceRect->x = 0.0f;
|
||||
sourceRect->y = 0.0f;
|
||||
sourceRect->width = (float)gameWidth;
|
||||
|
|
|
|||
|
|
@ -84,19 +84,19 @@ int main(void)
|
|||
for (int y = playerCellY - 1; y <= playerCellY + 1; y++)
|
||||
{
|
||||
// Avoid map accessing out of bounds
|
||||
if ((y < 0) || (y >= cubicmap.height)) continue;
|
||||
|
||||
for (int x = playerCellX - 1; x <= playerCellX + 1; x++)
|
||||
if ((y >= 0) && (y < cubicmap.height))
|
||||
{
|
||||
// Avoid map accessing out of bounds
|
||||
if ((x < 0) || (x >= cubicmap.width)) continue;
|
||||
|
||||
if ((mapPixels[y*cubicmap.width + x].r == 255) && // Collision: white pixel, only check R channel
|
||||
(CheckCollisionCircleRec(playerPos, playerRadius,
|
||||
(Rectangle){ mapPosition.x - 0.5f + x*1.0f, mapPosition.z - 0.5f + y*1.0f, 1.0f, 1.0f })))
|
||||
for (int x = playerCellX - 1; x <= playerCellX + 1; x++)
|
||||
{
|
||||
// Collision detected, reset camera position
|
||||
camera.position = oldCamPos;
|
||||
// NOTE: Collision: Only checking R channel for white pixel
|
||||
if (((x >= 0) && (x < cubicmap.width)) &&
|
||||
(mapPixels[y*cubicmap.width + x].r == 255) &&
|
||||
(CheckCollisionCircleRec(playerPos, playerRadius,
|
||||
(Rectangle){ mapPosition.x - 0.5f + x*1.0f, mapPosition.z - 0.5f + y*1.0f, 1.0f, 1.0f })))
|
||||
{
|
||||
// Collision detected, reset camera position
|
||||
camera.position = oldCamPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,25 +148,25 @@ void DrawSphereBasic(Color color)
|
|||
{
|
||||
for (int j = 0; j < slices; j++)
|
||||
{
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)),
|
||||
sinf(DEG2RAD*(270+(180/(rings + 1))*i)),
|
||||
cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)),
|
||||
sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
|
||||
cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)),
|
||||
sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
|
||||
cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*sinf(DEG2RAD*(j*360.0f/slices)),
|
||||
sinf(DEG2RAD*(270+(180.0f/(rings + 1))*i)),
|
||||
cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*cosf(DEG2RAD*(j*360.0f/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
|
||||
sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
|
||||
cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360.0f/slices)),
|
||||
sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
|
||||
cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360.0f/slices)));
|
||||
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)),
|
||||
sinf(DEG2RAD*(270+(180/(rings + 1))*i)),
|
||||
cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)),
|
||||
sinf(DEG2RAD*(270+(180/(rings + 1))*(i))),
|
||||
cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)),
|
||||
sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))),
|
||||
cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*sinf(DEG2RAD*(j*360.0f/slices)),
|
||||
sinf(DEG2RAD*(270+(180.0f/(rings + 1))*i)),
|
||||
cosf(DEG2RAD*(270+(180.0f/(rings + 1))*i))*cosf(DEG2RAD*(j*360.0f/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
|
||||
sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i))),
|
||||
cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
|
||||
rlVertex3f(cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360.0f/slices)),
|
||||
sinf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1))),
|
||||
cosf(DEG2RAD*(270+(180.0f/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360.0f/slices)));
|
||||
}
|
||||
}
|
||||
rlEnd();
|
||||
|
|
|
|||
|
|
@ -85,9 +85,9 @@ int main(void)
|
|||
|
||||
// Calculate the cube position
|
||||
Vector3 cubePos = {
|
||||
(float)(x - numBlocks/2)*(scale*3.0f) + scatter,
|
||||
(float)(y - numBlocks/2)*(scale*2.0f) + scatter,
|
||||
(float)(z - numBlocks/2)*(scale*3.0f) + scatter
|
||||
(float)(x - (float)numBlocks/2)*(scale*3.0f) + scatter,
|
||||
(float)(y - (float)numBlocks/2)*(scale*2.0f) + scatter,
|
||||
(float)(z - (float)numBlocks/2)*(scale*3.0f) + scatter
|
||||
};
|
||||
|
||||
// Pick a color with a hue depending on cube position for the rainbow color effect
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_DESKTOP_SDL)
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
#define GLAD_GLES2_IMPLEMENTATION
|
||||
#include "glad_gles2.h" // Required for: OpenGL functionality
|
||||
#define glGenVertexArrays glGenVertexArraysOES
|
||||
#define glBindVertexArray glBindVertexArrayOES
|
||||
|
|
|
|||
|
|
@ -258,8 +258,8 @@ int main(void)
|
|||
UnloadImage(pattern);
|
||||
|
||||
mode = MODE_PAUSE;
|
||||
offsetX = worldWidth*presetPatterns[preset].position.x - windowWidth/zoom/2.0f;
|
||||
offsetY = worldHeight*presetPatterns[preset].position.y - windowHeight/zoom/2.0f;
|
||||
offsetX = worldWidth*presetPatterns[preset].position.x - (float)windowWidth/zoom/2.0f;
|
||||
offsetY = worldHeight*presetPatterns[preset].position.y - (float)windowHeight/zoom/2.0f;
|
||||
}
|
||||
|
||||
// Check window draw inside world limits
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ int main(void)
|
|||
for (int i = 0; i < MAX_COLORS_COUNT; i++)
|
||||
{
|
||||
colorsRecs[i].x = 20.0f + 100.0f *(i%7) + 10.0f *(i%7);
|
||||
colorsRecs[i].y = 80.0f + 100.0f *(i/7) + 10.0f *(i/7);
|
||||
colorsRecs[i].y = 80.0f + 100.0f *((float)i/7) + 10.0f *((float)i/7);
|
||||
colorsRecs[i].width = 100.0f;
|
||||
colorsRecs[i].height = 100.0f;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ static void DrawDisplaySegment(Vector2 center, int length, int thick, bool verti
|
|||
(Vector2){ center.x + thick/2.0f, center.y - length/2.0f }, // Point 3
|
||||
(Vector2){ center.x - thick/2.0f, center.y + length/2.0f }, // Point 4
|
||||
(Vector2){ center.x + thick/2.0f, center.y + length/2.0f }, // Point 5
|
||||
(Vector2){ center.x, center.y + length/2 + thick/2.0f }, // Point 6
|
||||
(Vector2){ center.x, center.y + (float)length/2 + thick/2.0f }, // Point 6
|
||||
};
|
||||
|
||||
DrawTriangleStrip(segmentPointsV, 6, color);
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ int main(void)
|
|||
float totalM = m1 + m2;
|
||||
|
||||
Vector2 previousPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2);
|
||||
previousPosition.x += (screenWidth/2);
|
||||
previousPosition.y += (screenHeight/2 - 100);
|
||||
previousPosition.x += ((float)screenWidth/2);
|
||||
previousPosition.y += ((float)screenHeight/2 - 100);
|
||||
|
||||
// Scale length
|
||||
float L1 = l1*lengthScaler;
|
||||
|
|
@ -105,8 +105,8 @@ int main(void)
|
|||
|
||||
// Calculate position
|
||||
Vector2 currentPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2);
|
||||
currentPosition.x += screenWidth/2;
|
||||
currentPosition.y += screenHeight/2 - 100;
|
||||
currentPosition.x += (float)screenWidth/2;
|
||||
currentPosition.y += (float)screenHeight/2 - 100;
|
||||
|
||||
// Draw to render texture
|
||||
BeginTextureMode(target);
|
||||
|
|
|
|||
|
|
@ -97,8 +97,8 @@ int main(void)
|
|||
if (currentFont == 0) textSize = MeasureTextEx(fontDefault, msg, fontSize, 0);
|
||||
else textSize = MeasureTextEx(fontSDF, msg, fontSize, 0);
|
||||
|
||||
fontPosition.x = GetScreenWidth()/2 - textSize.x/2;
|
||||
fontPosition.y = GetScreenHeight()/2 - textSize.y/2 + 80;
|
||||
fontPosition.x = (float)GetScreenWidth()/2 - textSize.x/2;
|
||||
fontPosition.y = (float)GetScreenHeight()/2 - textSize.y/2 + 80;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
|
|
|
|||
|
|
@ -180,12 +180,12 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float
|
|||
if (text[i - 1] == 'c')
|
||||
{
|
||||
colFront = GetColor(colHexValue);
|
||||
colFront.a = (unsigned char)(colFront.a * (float)color.a/255.0f);
|
||||
//colFront.a *= (unsigned char)(colFront.a*(float)color.a/255.0f); // TODO: Review
|
||||
}
|
||||
else if (text[i - 1] == 'b')
|
||||
{
|
||||
colBack = GetColor(colHexValue);
|
||||
colBack.a *= (unsigned char)(colFront.a * (float)color.a / 255.0f);
|
||||
//colBack.a *= (unsigned char)(colFront.a*(float)color.a/255.0f);
|
||||
}
|
||||
|
||||
i += (colHexCount + 1); // Skip color value retrieved and ']'
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
|
|||
{
|
||||
if (!wordWrap)
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -234,7 +234,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
|
|||
{
|
||||
if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +258,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
|
|||
|
||||
if (wordWrap && (i == endLine))
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
startLine = endLine;
|
||||
endLine = -1;
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ int main(void)
|
|||
DrawTriangle(a, b, c, emoji[selected].color);
|
||||
|
||||
// Draw the main text message
|
||||
Rectangle textRect = { msgRect.x + horizontalPadding/2, msgRect.y + verticalPadding/2, msgRect.width - horizontalPadding, msgRect.height };
|
||||
Rectangle textRect = { msgRect.x + (float)horizontalPadding/2, msgRect.y + (float)verticalPadding/2, msgRect.width - horizontalPadding, msgRect.height };
|
||||
DrawTextBoxed(*font, messages[message].text, textRect, (float)font->baseSize, 1.0f, true, WHITE);
|
||||
|
||||
// Draw the info text below the main message
|
||||
|
|
@ -421,7 +421,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
|
|||
{
|
||||
if (!wordWrap)
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -429,7 +429,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
|
|||
{
|
||||
if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
}
|
||||
|
||||
|
|
@ -453,7 +453,7 @@ static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec,
|
|||
|
||||
if (wordWrap && (i == endLine))
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetY += (font.baseSize + (float)font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
startLine = endLine;
|
||||
endLine = -1;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ int main(void)
|
|||
InitWindow(screenWidth, screenHeight, "raylib [text] example - words alignment");
|
||||
|
||||
// Define the rectangle we will draw the text in
|
||||
Rectangle textContainerRect = (Rectangle){ screenWidth/2-screenWidth/4, screenHeight/2-screenHeight/3, screenWidth/2, screenHeight*2/3 };
|
||||
Rectangle textContainerRect = (Rectangle){ (float)screenWidth/2-(float)screenWidth/4, (float)screenHeight/2-(float)screenHeight/3, (float)screenWidth/2, (float)screenHeight*2/3 };
|
||||
|
||||
// Some text to display the current alignment
|
||||
const char *textAlignNameH[] = { "Left", "Centre", "Right" };
|
||||
|
|
|
|||
|
|
@ -83,10 +83,10 @@ int main(void)
|
|||
bunnies[i].position.x += bunnies[i].speed.x;
|
||||
bunnies[i].position.y += bunnies[i].speed.y;
|
||||
|
||||
if (((bunnies[i].position.x + texBunny.width/2) > GetScreenWidth()) ||
|
||||
((bunnies[i].position.x + texBunny.width/2) < 0)) bunnies[i].speed.x *= -1;
|
||||
if (((bunnies[i].position.y + texBunny.height/2) > GetScreenHeight()) ||
|
||||
((bunnies[i].position.y + texBunny.height/2 - 40) < 0)) bunnies[i].speed.y *= -1;
|
||||
if (((bunnies[i].position.x + (float)texBunny.width/2) > GetScreenWidth()) ||
|
||||
((bunnies[i].position.x + (float)texBunny.width/2) < 0)) bunnies[i].speed.x *= -1;
|
||||
if (((bunnies[i].position.y + (float)texBunny.height/2) > GetScreenHeight()) ||
|
||||
((bunnies[i].position.y + (float)texBunny.height/2 - 40) < 0)) bunnies[i].speed.y *= -1;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue