From 8f60996b6482246cb8f66d0ba8f6aa1604e6dd01 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 17 Oct 2016 00:03:38 +0200 Subject: [PATCH 01/32] Corrected some warnings --- src/audio.c | 6 +-- src/models.c | 116 ++++++++++++++++++++++++------------------------- src/raylib.h | 2 +- src/rlgl.c | 10 ++--- src/shapes.c | 22 +++++----- src/textures.c | 12 ++--- 6 files changed, 84 insertions(+), 84 deletions(-) diff --git a/src/audio.c b/src/audio.c index 9d2eeb47f..3684e10a1 100644 --- a/src/audio.c +++ b/src/audio.c @@ -706,7 +706,7 @@ Music LoadMusicStream(const char *fileName) else { music->stream = InitAudioStream(music->ctxFlac->sampleRate, music->ctxFlac->bitsPerSample, music->ctxFlac->channels); - music->totalSamples = music->ctxFlac->totalSampleCount; + music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount; music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_FLAC; music->loop = true; // We loop by default @@ -853,7 +853,7 @@ void UpdateMusicStream(Music music) int pcmi[AUDIO_BUFFER_SIZE]; // NOTE: Returns the number of samples to process (should be the same as numSamples) - int numSamplesFlac = drflac_read_s32(music->ctxFlac, numSamples, pcmi); + unsigned int numSamplesFlac = (unsigned int)drflac_read_s32(music->ctxFlac, numSamples, pcmi); UpdateAudioStream(music->stream, pcmi, numSamplesFlac*music->stream.channels); music->samplesLeft -= (numSamples*music->stream.channels); @@ -1237,7 +1237,7 @@ static Wave LoadOGG(const char *fileName) if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); - int totalSamples = totalSeconds*info.sample_rate*info.channels; + int totalSamples = (int)(totalSeconds*info.sample_rate*info.channels); wave.sampleCount = totalSamples; wave.data = (short *)malloc(totalSamplesLength*sizeof(short)); diff --git a/src/models.c b/src/models.c index 822da6e92..55ac78930 100644 --- a/src/models.c +++ b/src/models.c @@ -87,8 +87,8 @@ void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rot { rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex3f(sin(DEG2RAD*i)*radius, cos(DEG2RAD*i)*radius, 0.0f); - rlVertex3f(sin(DEG2RAD*(i + 10))*radius, cos(DEG2RAD*(i + 10))*radius, 0.0f); + rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f); + rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f); } rlEnd(); rlPopMatrix(); @@ -325,25 +325,25 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color { for (int j = 0; j < slices; j++) { - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*(j*360/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+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(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/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))); } } rlEnd(); @@ -364,26 +364,26 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col { for (int j = 0; j < slices; j++) { - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/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+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(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(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(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*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/(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))); } } rlEnd(); @@ -407,21 +407,21 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h // Draw Body ------------------------------------------------------------------------------------- for (int i = 0; i < 360; i += 360/sides) { - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); //Bottom Left - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); //Bottom Right - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); //Top Right + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); //Bottom Right + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); //Top Right - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); //Top Left - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); //Bottom Left - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); //Top Right + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); //Top Left + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); //Top Right } // Draw Cap -------------------------------------------------------------------------------------- for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, height, 0); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); } } else @@ -430,8 +430,8 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, height, 0); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); } } @@ -439,8 +439,8 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, 0, 0); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); } rlEnd(); rlPopMatrix(); @@ -460,17 +460,17 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl for (int i = 0; i < 360; i += 360/sides) { - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); } rlEnd(); rlPopMatrix(); diff --git a/src/raylib.h b/src/raylib.h index 5834d1c93..1433268b0 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -93,7 +93,7 @@ // Some basic Defines //---------------------------------------------------------------------------------- #ifndef PI - #define PI 3.14159265358979323846 + #define PI 3.14159265358979323846f #endif #define DEG2RAD (PI/180.0f) diff --git a/src/rlgl.c b/src/rlgl.c index e8607925b..a754678ca 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2653,7 +2653,7 @@ void InitVrDevice(int vrDevice) hmd.hResolution = 2160; // HMD horizontal resolution in pixels hmd.vResolution = 1200; // HMD vertical resolution in pixels hmd.hScreenSize = 0.133793f; // HMD horizontal size in meters - hmd.vScreenSize = 0.0669; // HMD vertical size in meters + hmd.vScreenSize = 0.0669f; // HMD vertical size in meters hmd.vScreenCenter = 0.04678f; // HMD screen center in meters hmd.eyeToScreenDistance = 0.041f; // HMD distance between eye and display in meters hmd.lensSeparationDistance = 0.07f; // HMD lens separation distance in meters @@ -3786,8 +3786,8 @@ static void SetStereoConfig(VrDeviceInfo hmd) // Compute lens parameters float lensShift = (hmd.hScreenSize*0.25f - hmd.lensSeparationDistance*0.5f)/hmd.hScreenSize; - float leftLensCenter[2] = { 0.25 + lensShift, 0.5f }; - float rightLensCenter[2] = { 0.75 - lensShift, 0.5f }; + float leftLensCenter[2] = { 0.25f + lensShift, 0.5f }; + float rightLensCenter[2] = { 0.75f - lensShift, 0.5f }; float leftScreenCenter[2] = { 0.25f, 0.5f }; float rightScreenCenter[2] = { 0.75f, 0.5f }; @@ -3804,8 +3804,8 @@ static void SetStereoConfig(VrDeviceInfo hmd) float normScreenWidth = 0.5f; float normScreenHeight = 1.0f; - float scaleIn[2] = { 2/normScreenWidth, 2/normScreenHeight/aspect }; - float scale[2] = { normScreenWidth*0.5/distortionScale, normScreenHeight*0.5*aspect/distortionScale }; + float scaleIn[2] = { 2.0f/normScreenWidth, 2.0f/normScreenHeight/aspect }; + float scale[2] = { normScreenWidth*0.5f/distortionScale, normScreenHeight*0.5f*aspect/distortionScale }; TraceLog(DEBUG, "VR: Distortion Shader: LeftLensCenter = { %f, %f }", leftLensCenter[0], leftLensCenter[1]); TraceLog(DEBUG, "VR: Distortion Shader: RightLensCenter = { %f, %f }", rightLensCenter[0], rightLensCenter[1]); diff --git a/src/shapes.c b/src/shapes.c index 9fcbeff72..62076b2c8 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -71,7 +71,7 @@ void DrawPixelV(Vector2 position, Color color) rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(position.x, position.y); - rlVertex2i(position.x + 1, position.y + 1); + rlVertex2f(position.x + 1.0f, position.y + 1.0f); rlEnd(); } @@ -98,7 +98,7 @@ void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) // Draw a color-filled circle void DrawCircle(int centerX, int centerY, float radius, Color color) { - DrawCircleV((Vector2){ centerX, centerY }, radius, color); + DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color); } // Draw a gradient-filled circle @@ -111,9 +111,9 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(centerX, centerY); rlColor4ub(color2.r, color2.g, color2.b, color2.a); - rlVertex2f(centerX + sin(DEG2RAD*i)*radius, centerY + cos(DEG2RAD*i)*radius); + rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); rlColor4ub(color2.r, color2.g, color2.b, color2.a); - rlVertex2f(centerX + sin(DEG2RAD*(i + 10))*radius, centerY + cos(DEG2RAD*(i + 10))*radius); + rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); } rlEnd(); } @@ -130,8 +130,8 @@ void DrawCircleV(Vector2 center, float radius, Color color) rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(center.x, center.y); - rlVertex2f(center.x + sin(DEG2RAD*i)*radius, center.y + cos(DEG2RAD*i)*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 10))*radius, center.y + cos(DEG2RAD*(i + 10))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); } rlEnd(); } @@ -145,9 +145,9 @@ void DrawCircleV(Vector2 center, float radius, Color color) rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(center.x, center.y); - rlVertex2f(center.x + sin(DEG2RAD*i)*radius, center.y + cos(DEG2RAD*i)*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 10))*radius, center.y + cos(DEG2RAD*(i + 10))*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 20))*radius, center.y + cos(DEG2RAD*(i + 20))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 20))*radius, center.y + cosf(DEG2RAD*(i + 20))*radius); } rlEnd(); @@ -164,8 +164,8 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color) // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) for (int i = 0; i < 360; i += 10) { - rlVertex2f(centerX + sin(DEG2RAD*i)*radius, centerY + cos(DEG2RAD*i)*radius); - rlVertex2f(centerX + sin(DEG2RAD*(i + 10))*radius, centerY + cos(DEG2RAD*(i + 10))*radius); + 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(); } diff --git a/src/textures.c b/src/textures.c index fd5bdd80c..323c0a8a9 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1118,7 +1118,7 @@ Image ImageText(const char *text, int fontSize, Color color) if (fontSize < defaultFontSize) fontSize = defaultFontSize; int spacing = fontSize/defaultFontSize; - Image imText = ImageTextEx(GetDefaultFont(), text, fontSize, spacing, color); + Image imText = ImageTextEx(GetDefaultFont(), text, (float)fontSize, spacing, color); return imText; } @@ -1183,7 +1183,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color) { // NOTE: For default font, sapcing is set to desired font size / default font size (10) - ImageDrawTextEx(dst, position, GetDefaultFont(), text, fontSize, fontSize/10, color); + ImageDrawTextEx(dst, position, GetDefaultFont(), text, (float)fontSize, fontSize/10, color); } // Draw text (custom sprite font) within an image (destination) @@ -1317,7 +1317,7 @@ void ImageColorContrast(Image *image, float contrast) if (contrast < -100) contrast = -100; if (contrast > 100) contrast = 100; - contrast = (100.0 + contrast)/100.0; + contrast = (100.0f + contrast)/100.0f; contrast *= contrast; Color *pixels = GetImageData(*image); @@ -1326,7 +1326,7 @@ void ImageColorContrast(Image *image, float contrast) { for (int x = 0; x < image->width; x++) { - float pR = (float)pixels[y*image->width + x].r/255.0; + float pR = (float)pixels[y*image->width + x].r/255.0f; pR -= 0.5; pR *= contrast; pR += 0.5; @@ -1334,7 +1334,7 @@ void ImageColorContrast(Image *image, float contrast) if (pR < 0) pR = 0; if (pR > 255) pR = 255; - float pG = (float)pixels[y*image->width + x].g/255.0; + float pG = (float)pixels[y*image->width + x].g/255.0f; pG -= 0.5; pG *= contrast; pG += 0.5; @@ -1342,7 +1342,7 @@ void ImageColorContrast(Image *image, float contrast) if (pG < 0) pG = 0; if (pG > 255) pG = 255; - float pB = (float)pixels[y*image->width + x].b/255.0; + float pB = (float)pixels[y*image->width + x].b/255.0f; pB -= 0.5; pB *= contrast; pB += 0.5; From d5e0f4e84eb9c8281be7cae8a4a38c231fc4a664 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 17 Oct 2016 17:02:33 +0200 Subject: [PATCH 02/32] Added notes on vr tracking -> camera update --- src/rlgl.c | 24 ++++++++++++------------ src/rlgl.h | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/rlgl.c b/src/rlgl.c index a754678ca..806879586 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -372,11 +372,11 @@ static char *ReadTextFile(const char *fileName); // Read chars array from #if defined(RLGL_OCULUS_SUPPORT) #if !defined(RLGL_STANDALONE) -static bool InitOculusDevice(void); // Initialize Oculus device (returns true if success) -static void CloseOculusDevice(void); // Close Oculus device -static void UpdateOculusTracking(void); // Update Oculus head position-orientation tracking -static void BeginOculusDrawing(void); // Setup Oculus buffers for drawing -static void EndOculusDrawing(void); // Finish Oculus drawing and blit framebuffer to mirror +static bool InitOculusDevice(void); // Initialize Oculus device (returns true if success) +static void CloseOculusDevice(void); // Close Oculus device +static void UpdateOculusTracking(Camera *camera); // Update Oculus head position-orientation tracking +static void BeginOculusDrawing(void); // Setup Oculus buffers for drawing +static void EndOculusDrawing(void); // Finish Oculus drawing and blit framebuffer to mirror #endif static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height); // Load Oculus required buffers @@ -2735,15 +2735,11 @@ void ToggleVrMode(void) } // Update VR tracking (position and orientation) and camera +// NOTE: Camera (position, target, up) gets update with head tracking information void UpdateVrTracking(Camera *camera) { #if defined(RLGL_OCULUS_SUPPORT) - if (vrDeviceReady) - { - UpdateOculusTracking(); - - // TODO: Update camera data (position, target, up) with tracking data - } + if (vrDeviceReady) UpdateOculusTracking(camera); #endif } @@ -4083,7 +4079,7 @@ OCULUSAPI void CloseOculusDevice(void) } // Update Oculus head position-orientation tracking -OCULUSAPI void UpdateOculusTracking(void) +OCULUSAPI void UpdateOculusTracking(Camera *camera) { frameIndex++; @@ -4093,6 +4089,10 @@ OCULUSAPI void UpdateOculusTracking(void) layer.eyeLayer.RenderPose[0] = eyePoses[0]; layer.eyeLayer.RenderPose[1] = eyePoses[1]; + // TODO: Update external camera with eyePoses data (position, orientation) + // NOTE: We can simplify to simple camera if we consider IPD and HMD device configuration again later + // it will be useful for the user to draw, lets say, billboards oriented to camera + // Get session status information ovrSessionStatus sessionStatus; ovr_GetSessionStatus(session, &sessionStatus); diff --git a/src/rlgl.h b/src/rlgl.h index 3a47b4c8f..d5a39aaf7 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -381,7 +381,7 @@ void ToggleVrMode(void); // Enable/Disable VR experience (dev // Oculus Rift API for direct access the device (no simulator) bool InitOculusDevice(void); // Initialize Oculus device (returns true if success) void CloseOculusDevice(void); // Close Oculus device -void UpdateOculusTracking(void); // Update Oculus head position-orientation tracking +void UpdateOculusTracking(Camera *camera); // Update Oculus head position-orientation tracking (and camera) void BeginOculusDrawing(void); // Setup Oculus buffers for drawing void EndOculusDrawing(void); // Finish Oculus drawing and blit framebuffer to mirror #endif From 0ce7f0c4094fa8a6cc74c410aee37413034cb0b9 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 17 Oct 2016 18:18:13 +0200 Subject: [PATCH 03/32] Some work on multiple inputs... - Corrected bug and tested new gamepad system - Reviewed Android key inputs system, unified with desktop - Reorganize mouse functions on core --- src/core.c | 199 ++++++++++++++++++++++++--------------------------- src/raylib.h | 36 +++++----- 2 files changed, 110 insertions(+), 125 deletions(-) diff --git a/src/core.c b/src/core.c index 3bd85fdd9..d044a66e8 100644 --- a/src/core.c +++ b/src/core.c @@ -131,7 +131,7 @@ #endif #define MAX_GAMEPADS 4 // Max number of gamepads supported -#define MAX_GAMEPAD_BUTTONS 11 // Max bumber of buttons supported (per gamepad) +#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) #define RL_LOAD_DEFAULT_FONT // Load default font on window initialization (module: text) @@ -158,9 +158,6 @@ static const char *internalDataPath; // Android internal data path to static bool windowReady = false; // Used to detect display initialization static bool appEnabled = true; // Used to detec if app is active static bool contextRebindRequired = false; // Used to know context rebind required - -static int previousButtonState[128] = { 1 }; // Required to check if button pressed/released once -static int currentButtonState[128] = { 1 }; // Required to check if button pressed/released once #endif #if defined(PLATFORM_RPI) @@ -203,10 +200,6 @@ static Matrix downscaleView; // Matrix to downscale view (in case static const char *windowTitle; // Window text title... static bool cursorOnScreen = false; // Tracks if cursor is inside client area -// Register keyboard states -static char previousKeyState[512] = { 0 }; // Registers previous frame key state -static char currentKeyState[512] = { 0 }; // Registers current frame key state - // Register mouse states static char previousMouseState[3] = { 0 }; // Registers previous mouse button state static char currentMouseState[3] = { 0 }; // Registers current mouse button state @@ -221,11 +214,16 @@ static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS] = { 0 }; // Keyboard configuration static int exitKey = KEY_ESCAPE; // Default exit key (ESC) -static int lastKeyPressed = -1; // Register last key pressed static bool cursorHidden; // Track if cursor is hidden #endif +// Register keyboard states +static char previousKeyState[512] = { 0 }; // Registers previous frame key state +static char currentKeyState[512] = { 0 }; // Registers current frame key state + +static int lastKeyPressed = -1; // Register last key pressed + static Vector2 mousePosition; // Mouse position on screen static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen @@ -526,6 +524,63 @@ int GetScreenHeight(void) return screenHeight; } +// Show mouse cursor +void ShowCursor() +{ +#if defined(PLATFORM_DESKTOP) + #ifdef __linux + XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window)); + #else + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + #endif +#endif + cursorHidden = false; +} + +// Hide mouse cursor +void HideCursor() +{ +#if defined(PLATFORM_DESKTOP) + #ifdef __linux + XColor Col; + const char Nil[] = {0}; + + Pixmap Pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), Nil, 1, 1); + Cursor Cur = XCreatePixmapCursor(glfwGetX11Display(), Pix, Pix, &Col, &Col, 0, 0); + + XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), Cur); + XFreeCursor(glfwGetX11Display(), Cur); + #else + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + #endif +#endif + cursorHidden = true; +} + +// Check if mouse cursor is hidden +bool IsCursorHidden() +{ + return cursorHidden; +} + +// Enable mouse cursor +void EnableCursor() +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +#endif + cursorHidden = false; +} + +// Disable mouse cursor +void DisableCursor() +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); +#endif + cursorHidden = true; +} + // Sets Background Color void ClearBackground(Color color) { @@ -1050,8 +1105,13 @@ bool IsKeyPressed(int key) { bool pressed = false; +#if defined(PLATFORM_ANDROID) + if ((currentButtonState[key] != previousButtonState[key]) && (currentButtonState[key] == 0)) pressed = true; + else pressed = false; +#else if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 1)) pressed = true; else pressed = false; +#endif return pressed; } @@ -1067,9 +1127,14 @@ bool IsKeyDown(int key) bool IsKeyReleased(int key) { bool released = false; - + +#if defined(PLATFORM_ANDROID) + if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 1)) released = true; + else released = false; +#else if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true; else released = false; +#endif return released; } @@ -1091,64 +1156,9 @@ int GetKeyPressed(void) // NOTE: default exitKey is ESCAPE void SetExitKey(int key) { +#if !defined(PLATFORM_ANDROID) exitKey = key; -} - -// Hide mouse cursor -void HideCursor() -{ -#if defined(PLATFORM_DESKTOP) - #ifdef __linux - XColor Col; - const char Nil[] = {0}; - - Pixmap Pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), Nil, 1, 1); - Cursor Cur = XCreatePixmapCursor(glfwGetX11Display(), Pix, Pix, &Col, &Col, 0, 0); - - XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), Cur); - XFreeCursor(glfwGetX11Display(), Cur); - #else - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - #endif #endif - cursorHidden = true; -} - -// Show mouse cursor -void ShowCursor() -{ -#if defined(PLATFORM_DESKTOP) - #ifdef __linux - XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window)); - #else - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - #endif -#endif - cursorHidden = false; -} - -// Disable mouse cursor -void DisableCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); -#endif - cursorHidden = true; -} - -// Enable mouse cursor -void EnableCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); -#endif - cursorHidden = false; -} - -// Check if mouse cursor is hidden -bool IsCursorHidden() -{ - return cursorHidden; } // NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) @@ -1204,7 +1214,7 @@ bool IsGamepadButtonDown(int gamepad, int button) { bool result = false; - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] == 1)) result = true; return result; @@ -1387,37 +1397,6 @@ Vector2 GetTouchPosition(int index) return position; } -#if defined(PLATFORM_ANDROID) -// Detect if a button has been pressed once -bool IsButtonPressed(int button) -{ - bool pressed = false; - - if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 0)) pressed = true; - else pressed = false; - - return pressed; -} - -// Detect if a button is being pressed (button held down) -bool IsButtonDown(int button) -{ - if (currentButtonState[button] == 0) return true; - else return false; -} - -// Detect if a button has been released once -bool IsButtonReleased(int button) -{ - bool released = false; - - if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 1)) released = true; - else released = false; - - return released; -} -#endif - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -1900,8 +1879,9 @@ static bool GetKeyStatus(int key) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetKey(window, key); #elif defined(PLATFORM_ANDROID) - // TODO: Check for virtual keyboard - return false; + // NOTE: Android supports up to 260 keys + if (key < 0 || key > 260) return false; + else return currentKeyState[key]; #elif defined(PLATFORM_RPI) // NOTE: Keys states are filled in PollInputEvents() if (key < 0 || key > 511) return false; @@ -1929,6 +1909,9 @@ static void PollInputEvents(void) // NOTE: Gestures update must be called every frame to reset gestures correctly // because ProcessGestureEvent() is just called on an event, not every frame UpdateGestures(); + + // Reset last key pressed registered + lastKeyPressed = -1; #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -1939,9 +1922,8 @@ static void PollInputEvents(void) mousePosition.x = (float)mouseX; mousePosition.y = (float)mouseY; - + // Keyboard input polling (automatically managed by GLFW3 through callback) - lastKeyPressed = -1; // Register previous keys states for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i]; @@ -1971,7 +1953,7 @@ static void PollInputEvents(void) for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++) { - if (buttons[i] == GLFW_PRESS) currentGamepadState[i][k] = 1; + if (buttons[k] == GLFW_PRESS) currentGamepadState[i][k] = 1; else currentGamepadState[i][k] = 0; } @@ -1994,7 +1976,8 @@ static void PollInputEvents(void) #if defined(PLATFORM_ANDROID) // Register previous keys states - for (int i = 0; i < 128; i++) previousButtonState[i] = currentButtonState[i]; + // NOTE: Android supports up to 260 keys + for (int i = 0; i < 260; i++) previousKeyState[i] = currentKeyState[i]; // Poll Events (registered events) // NOTE: Activity is paused if not enabled (appEnabled) @@ -2371,7 +2354,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) //int32_t AKeyEvent_getMetaState(event); // Save current button and its state - currentButtonState[keycode] = AKeyEvent_getAction(event); // Down = 0, Up = 1 + // NOTE: Android key action is 0 for down and 1 for up + if (AKeyEvent_getAction(event) == 0) + { + currentKeyState[keycode] = 1; // Key down + lastKeyPressed = keycode; + } + else currentKeyState[keycode] = 0; // Key up if (keycode == AKEYCODE_POWER) { diff --git a/src/raylib.h b/src/raylib.h index 1433268b0..c1ac2416f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -174,6 +174,14 @@ #define KEY_Y 89 #define KEY_Z 90 +#if defined(PLATFORM_ANDROID) + // Android Physical Buttons + #define KEY_BACK 4 + #define KEY_MENU 82 + #define KEY_VOLUME_UP 24 + #define KEY_VOLUME_DOWN 25 +#endif + // Mouse Buttons #define MOUSE_LEFT_BUTTON 0 #define MOUSE_RIGHT_BUTTON 1 @@ -213,6 +221,13 @@ #define GAMEPAD_XBOX_BUTTON_RB 5 #define GAMEPAD_XBOX_BUTTON_SELECT 6 #define GAMEPAD_XBOX_BUTTON_START 7 +#define GAMEPAD_XBOX_BUTTON_UP 10 +#define GAMEPAD_XBOX_BUTTON_RIGHT 11 +#define GAMEPAD_XBOX_BUTTON_DOWN 12 +#define GAMEPAD_XBOX_BUTTON_LEFT 13 + +#define GAMEPAD_XBOX_AXIS_LEFT_X 0 +#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 #if defined(PLATFORM_RPI) #define GAMEPAD_XBOX_AXIS_DPAD_X 7 @@ -222,24 +237,11 @@ #define GAMEPAD_XBOX_AXIS_LT 2 #define GAMEPAD_XBOX_AXIS_RT 5 #else - #define GAMEPAD_XBOX_BUTTON_UP 10 - #define GAMEPAD_XBOX_BUTTON_DOWN 12 - #define GAMEPAD_XBOX_BUTTON_LEFT 13 - #define GAMEPAD_XBOX_BUTTON_RIGHT 11 #define GAMEPAD_XBOX_AXIS_RIGHT_X 4 #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 #define GAMEPAD_XBOX_AXIS_LT_RT 2 #endif -#define GAMEPAD_XBOX_AXIS_LEFT_X 0 -#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 - -// Android Physic Buttons -#define ANDROID_BACK 4 -#define ANDROID_MENU 82 -#define ANDROID_VOLUME_UP 24 -#define ANDROID_VOLUME_DOWN 25 - // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. #ifdef __cplusplus @@ -648,7 +650,6 @@ RLAPI int StorageLoadValue(int position); // Storage loa //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) //------------------------------------------------------------------------------------ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI bool IsKeyPressed(int key); // Detect if a key has been pressed once RLAPI bool IsKeyDown(int key); // Detect if a key is being pressed RLAPI bool IsKeyReleased(int key); // Detect if a key has been released once @@ -656,6 +657,7 @@ RLAPI bool IsKeyUp(int key); // Detect if a key RLAPI int GetKeyPressed(void); // Get latest key pressed RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis @@ -679,12 +681,6 @@ RLAPI int GetTouchX(void); // Returns touch p RLAPI int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) RLAPI Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) -#if defined(PLATFORM_ANDROID) -bool IsButtonPressed(int button); // Detect if an android physic button has been pressed -bool IsButtonDown(int button); // Detect if an android physic button is being pressed -bool IsButtonReleased(int button); // Detect if an android physic button has been released -#endif - //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ From b8ce6805117bcd28f80ae92f7faa14abdcb2f741 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 18 Oct 2016 00:15:23 +0200 Subject: [PATCH 04/32] Improved Android support --- src/core.c | 21 ++++++--------------- src/raylib.h | 8 +++----- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/core.c b/src/core.c index d044a66e8..b8a8ac051 100644 --- a/src/core.c +++ b/src/core.c @@ -79,8 +79,7 @@ #endif #if defined(PLATFORM_ANDROID) - #include // Java native interface - #include // Android sensors functions + //#include // Android sensors functions (accelerometer, gyroscope, light...) #include // Defines AWINDOW_FLAG_FULLSCREEN and others #include // Defines basic app state struct and manages activity @@ -361,7 +360,7 @@ void InitWindow(int width, int height, const char *title) #if defined(PLATFORM_ANDROID) // Android activity initialization -void InitWindow(int width, int height, struct android_app *state) +void InitWindow(int width, int height, void *state) { TraceLog(INFO, "Initializing raylib (v1.6.0)"); @@ -370,7 +369,7 @@ void InitWindow(int width, int height, struct android_app *state) screenWidth = width; screenHeight = height; - app = state; + app = (struct android_app *)state; internalDataPath = app->activity->internalDataPath; // Set desired windows flags before initializing anything @@ -524,6 +523,7 @@ int GetScreenHeight(void) return screenHeight; } +#if !defined(PLATFORM_ANDROID) // Show mouse cursor void ShowCursor() { @@ -580,6 +580,7 @@ void DisableCursor() #endif cursorHidden = true; } +#endif // !defined(PLATFORM_ANDROID) // Sets Background Color void ClearBackground(Color color) @@ -1099,19 +1100,13 @@ Matrix GetCameraMatrix(Camera camera) //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //---------------------------------------------------------------------------------- -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Detect if a key has been pressed once bool IsKeyPressed(int key) { bool pressed = false; -#if defined(PLATFORM_ANDROID) - if ((currentButtonState[key] != previousButtonState[key]) && (currentButtonState[key] == 0)) pressed = true; - else pressed = false; -#else if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 1)) pressed = true; else pressed = false; -#endif return pressed; } @@ -1128,13 +1123,8 @@ bool IsKeyReleased(int key) { bool released = false; -#if defined(PLATFORM_ANDROID) - if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 1)) released = true; - else released = false; -#else if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true; else released = false; -#endif return released; } @@ -1161,6 +1151,7 @@ void SetExitKey(int key) #endif } +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) // Detect if a gamepad is available diff --git a/src/raylib.h b/src/raylib.h index c1ac2416f..efb9a71c9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -77,10 +77,6 @@ #define PLATFORM_DESKTOP #endif -#if defined(PLATFORM_ANDROID) - typedef struct android_app; // Define android_app struct (android_native_app_glue.h) -#endif - #if defined(_WIN32) && defined(BUILDING_DLL) #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 DLL #elif defined(_WIN32) && defined(RAYLIB_DLL) @@ -591,7 +587,7 @@ extern "C" { // Prevents name mangling of functions // Window and Graphics Device Functions (Module: core) //------------------------------------------------------------------------------------ #if defined(PLATFORM_ANDROID) -RLAPI void InitWindow(int width, int height, struct android_app *state); // Init Android Activity and OpenGL Graphics +RLAPI void InitWindow(int width, int height, void *state); // Init Android Activity and OpenGL Graphics (struct android_app) #elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics #endif @@ -603,11 +599,13 @@ RLAPI void ToggleFullscreen(void); // Fullscreen RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height +#if !defined(PLATFORM_ANDROID) RLAPI void ShowCursor(void); // Shows cursor RLAPI void HideCursor(void); // Hides cursor RLAPI bool IsCursorHidden(void); // Returns true if cursor is not visible RLAPI void EnableCursor(void); // Enables cursor RLAPI void DisableCursor(void); // Disables cursor +#endif RLAPI void ClearBackground(Color color); // Sets Background Color RLAPI void BeginDrawing(void); // Setup drawing canvas to start drawing From 1142d4edae645f9e5b235c2c3278a8d16a1f97cf Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 24 Oct 2016 19:08:23 +0200 Subject: [PATCH 05/32] Force threads to finish on CloseWindow() --- src/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core.c b/src/core.c index b8a8ac051..dd005836c 100644 --- a/src/core.c +++ b/src/core.c @@ -463,6 +463,9 @@ void CloseWindow(void) // Wait for mouse and gamepad threads to finish before closing // NOTE: Those threads should already have finished at this point // because they are controlled by windowShouldClose variable + + windowShouldClose = true; // Added to force threads to exit when the close window is called + pthread_join(mouseThreadId, NULL); pthread_join(gamepadThreadId, NULL); #endif From 6d34adbd60631001c124ebe48d8d059a5ee8d3d8 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 24 Oct 2016 19:11:29 +0200 Subject: [PATCH 06/32] Improving sprite fonts support... Support grayscale (8 bit) textures for fonts Load unordered chars data above char 126 --- src/text.c | 31 +++++++++++++++++++++++-------- src/textures.c | 37 +++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/text.c b/src/text.c index d1d7602ff..02bc1fe65 100644 --- a/src/text.c +++ b/src/text.c @@ -355,7 +355,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float else rec = spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR]; } - if (rec.x > 0) + if (rec.x >= 0) { DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x*scaleFactor, position.y + textOffsetY + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].y*scaleFactor, @@ -811,8 +811,12 @@ static SpriteFont LoadBMFont(const char *fileName) strncat(texPath, texFileName, strlen(texFileName)); TraceLog(DEBUG, "[%s] Font texture loading path: %s", fileName, texPath); + + Image imFont = LoadImage(texPath); - font.texture = LoadTexture(texPath); + if (imFont.format == UNCOMPRESSED_GRAYSCALE) ImageAlphaMask(&imFont, imFont); + + font.texture = LoadTextureFromImage(imFont); font.size = fontSize; font.numChars = numChars; font.charValues = (int *)malloc(numChars*sizeof(int)); @@ -820,12 +824,14 @@ static SpriteFont LoadBMFont(const char *fileName) font.charOffsets = (Vector2 *)malloc(numChars*sizeof(Vector2)); font.charAdvanceX = (int *)malloc(numChars*sizeof(int)); + UnloadImage(imFont); + free(texPath); int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; bool unorderedChars = false; - int firstChar = 0; + int firstChar = 32; for (int i = 0; i < numChars; i++) { @@ -833,8 +839,20 @@ static SpriteFont LoadBMFont(const char *fileName) sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); - if (i == 0) firstChar = charId; - else if (i != (charId - firstChar)) unorderedChars = true; + if ((i == 0) && (charId != FONT_FIRST_CHAR)) + { + TraceLog(WARNING, "BMFont not supported: expected SPACE(32) as first character, falling back to default font"); + firstChar = charId; + break; + } + else if ((i < (126 - FONT_FIRST_CHAR)) && (i != (charId - FONT_FIRST_CHAR))) + { + // NOTE: We expect the first 95 chars (32..126) to be ordered for quick drawing access, + // characters above are stored and we look for them (search algorythm) when drawing + TraceLog(WARNING, "BMFont not supported: unordered chars data, falling back to default font"); + unorderedChars = true; + break; + } // Save data properly in sprite font font.charValues[i] = charId; @@ -845,9 +863,6 @@ static SpriteFont LoadBMFont(const char *fileName) fclose(fntFile); - if (firstChar != FONT_FIRST_CHAR) TraceLog(WARNING, "BMFont not supported: expected SPACE(32) as first character, falling back to default font"); - else if (unorderedChars) TraceLog(WARNING, "BMFont not supported: unordered chars data, falling back to default font"); - // NOTE: Font data could be not ordered by charId: 32,33,34,35... raylib does not support unordered BMFonts if ((firstChar != FONT_FIRST_CHAR) || (unorderedChars) || (font.texture.id == 0)) { diff --git a/src/textures.c b/src/textures.c index 323c0a8a9..eab443b68 100644 --- a/src/textures.c +++ b/src/textures.c @@ -694,28 +694,45 @@ void ImageFormat(Image *image, int newFormat) } // Apply alpha mask to image -// NOTE 1: Returned image is RGBA - 32bit +// NOTE 1: Returned image is GRAY_ALPHA (16bit) or RGBA (32bit) // NOTE 2: alphaMask should be same size as image void ImageAlphaMask(Image *image, Image alphaMask) { - if (image->format >= COMPRESSED_DXT1_RGB) + if ((image->width != alphaMask.width) || (image->height != alphaMask.height)) + { + TraceLog(WARNING, "Alpha mask must be same size as image"); + } + else if (image->format >= COMPRESSED_DXT1_RGB) { TraceLog(WARNING, "Alpha mask can not be applied to compressed data formats"); - return; } else { // Force mask to be Grayscale Image mask = ImageCopy(alphaMask); - ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE); + if (mask.format != UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE); - // Convert image to RGBA - if (image->format != UNCOMPRESSED_R8G8B8A8) ImageFormat(image, UNCOMPRESSED_R8G8B8A8); - - // Apply alpha mask to alpha channel - for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4) + // In case image is only grayscale, we just add alpha channel + if (image->format == UNCOMPRESSED_GRAYSCALE) { - ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; + ImageFormat(image, UNCOMPRESSED_GRAY_ALPHA); + + // Apply alpha mask to alpha channel + for (int i = 0, k = 1; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2) + { + ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; + } + } + else + { + // Convert image to RGBA + if (image->format != UNCOMPRESSED_R8G8B8A8) ImageFormat(image, UNCOMPRESSED_R8G8B8A8); + + // Apply alpha mask to alpha channel + for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4) + { + ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; + } } UnloadImage(mask); From 137057f499f0c6a15ad7e306f27fc4d5c02933be Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 27 Oct 2016 13:39:47 +0200 Subject: [PATCH 07/32] Function added: GenSpriteFont() --- src/text.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/text.c b/src/text.c index 02bc1fe65..5e978823b 100644 --- a/src/text.c +++ b/src/text.c @@ -272,6 +272,27 @@ SpriteFont LoadSpriteFont(const char *fileName) return spriteFont; } +// Generate SpriteFont from TTF file +// NOTE: You can pass an array with desired characters, those characters should be available in the font +// if array is NULL, default char set is selected 32..126 +SpriteFont GenSpriteFont(const char *fileName, int fontSize, int *fontChars) +{ + SpriteFont spriteFont = { 0 }; + + if (strcmp(GetExtension(fileName),"ttf") == 0) + { + spriteFont = LoadTTF(fileName, fontSize, FONT_FIRST_CHAR, DEFAULT_TTF_NUMCHARS); + } + + if (spriteFont.texture.id == 0) + { + TraceLog(WARNING, "[%s] SpriteFont could not be generated, using default font", fileName); + spriteFont = GetDefaultFont(); + } + + return spriteFont; +} + // Unload SpriteFont from GPU memory void UnloadSpriteFont(SpriteFont spriteFont) { @@ -288,6 +309,7 @@ void UnloadSpriteFont(SpriteFont spriteFont) } } + // Draw text (using default font) // NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used // NOTE: chars spacing is proportional to fontSize From 5c80f650827337af8054446b21424d39349606d9 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 27 Oct 2016 13:40:17 +0200 Subject: [PATCH 08/32] Funtions added to set texture parameters SetTextureFilter() SetTextureWrap() --- src/textures.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/textures.c b/src/textures.c index eab443b68..867e565d5 100644 --- a/src/textures.c +++ b/src/textures.c @@ -442,6 +442,20 @@ void UnloadRenderTexture(RenderTexture2D target) if (target.id != 0) rlDeleteRenderTextures(target); } +// Set texture scale filter +void SetTextureFilter(Texture2D texture, int filterMode) +{ + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, filterMode); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, filterMode); +} + +// Set texture wrap mode +void SetTextureWrap(Texture2D texture, int wrapMode) +{ + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, wrapMode); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, wrapMode); +} + // Get pixel data from image in the form of Color struct array Color *GetImageData(Image image) { From 4ff98f34bbc3233f5eca61dfe07c2336c52918ce Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 27 Oct 2016 13:40:48 +0200 Subject: [PATCH 09/32] Function to set texture parameters -IN PROGRESS- --- src/rlgl.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/rlgl.h | 11 +++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/rlgl.c b/src/rlgl.c index 806879586..0a7e35836 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -871,6 +871,48 @@ void rlDisableTexture(void) #endif } +// Set texture parameters +// TODO: Review this function to choose right filter/wrap value +void rlTextureParameters(unsigned int id, int param, int value) +{ +/* +// TextureWrapMode +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F + +// TextureMagFilter +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 + +// TextureMinFilter +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +*/ + + int glValue = 0; + + glBindTexture(GL_TEXTURE_2D, id); + + switch (value) + { + case FILTER_POINT: glValue = GL_NEAREST; break; + case FILTER_BILINEAR: glValue = GL_LINEAR; break; + case FILTER_TRILINEAR: glValue = GL_LINEAR; break; + //case WRAP_REPEAT: glValue = GL_REPEAT; break; + //case WRAP_CLAMP: glValue = GL_CLAMP_TO_EDGE; break; + //case WRAP_MIRROR: glValue = GL_NEAREST; break; + default: break; + } + + glTexParameteri(GL_TEXTURE_2D, param, glValue); + + glBindTexture(GL_TEXTURE_2D, 0); +} + // Enable rendering to texture (fbo) void rlEnableRenderTexture(unsigned int id) { diff --git a/src/rlgl.h b/src/rlgl.h index d5a39aaf7..b6679ef68 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -90,15 +90,21 @@ #define MAX_QUADS_BATCH 1024 // Be careful with text, every letter maps a quad #endif +// Texture parameters (equivalent to OpenGL defines) +#define RL_TEXTURE_MAG_FILTER 0x2800 +#define RL_TEXTURE_MIN_FILTER 0x2801 +#define RL_TEXTURE_WRAP_S 0x2802 +#define RL_TEXTURE_WRAP_T 0x2803 + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- +typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; + typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode; typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode; -typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; - #if defined(RLGL_STANDALONE) #ifndef __cplusplus // Boolean type @@ -296,6 +302,7 @@ void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) //------------------------------------------------------------------------------------ void rlEnableTexture(unsigned int id); // Enable texture usage void rlDisableTexture(void); // Disable texture usage +void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap) void rlEnableRenderTexture(unsigned int id); // Enable render texture (fbo) void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer void rlEnableDepthTest(void); // Enable depth test From 02842a3e2fefe122baaf40da1bcae5548239d570 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 27 Oct 2016 13:41:43 +0200 Subject: [PATCH 10/32] Review gamepad inputs Added funtion: GetGamepadButtonPressed() - This function can be useful for custom gamepad configuration --- src/core.c | 19 +++++++++++++++- src/raylib.h | 61 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 19 deletions(-) diff --git a/src/core.c b/src/core.c index dd005836c..8646bf8f1 100644 --- a/src/core.c +++ b/src/core.c @@ -222,6 +222,7 @@ static char previousKeyState[512] = { 0 }; // Registers previous frame key stat static char currentKeyState[512] = { 0 }; // Registers current frame key state static int lastKeyPressed = -1; // Register last key pressed +static int lastGamepadButtonPressed = -1; // Register last gamepad button pressed static Vector2 mousePosition; // Mouse position on screen static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen @@ -1236,6 +1237,13 @@ bool IsGamepadButtonUp(int gamepad, int button) return result; } + +// Get the last gamepad button pressed +int GetGamepadButtonPressed(void) +{ + return lastGamepadButtonPressed; +} + #endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) @@ -1906,6 +1914,9 @@ static void PollInputEvents(void) // Reset last key pressed registered lastKeyPressed = -1; + + // Reset last gamepad button pressed registered + lastGamepadButtonPressed = -1; #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -1947,7 +1958,11 @@ static void PollInputEvents(void) for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++) { - if (buttons[k] == GLFW_PRESS) currentGamepadState[i][k] = 1; + if (buttons[k] == GLFW_PRESS) + { + currentGamepadState[i][k] = 1; + lastGamepadButtonPressed = k; + } else currentGamepadState[i][k] = 0; } @@ -2801,6 +2816,8 @@ static void *GamepadThread(void *arg) { // 1 - button pressed, 0 - button released currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value; + + if ((int)gamepadEvent.value == 1) lastGamepadButtonPressed = gamepadEvent.number; } } else if (gamepadEvent.type == JS_EVENT_AXIS) diff --git a/src/raylib.h b/src/raylib.h index efb9a71c9..491923dcc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -192,21 +192,32 @@ #define GAMEPAD_PLAYER3 2 #define GAMEPAD_PLAYER4 3 -// Gamepad Buttons +// Gamepad Buttons/Axis -// PS3 USB Controller -#define GAMEPAD_PS3_BUTTON_A 2 -#define GAMEPAD_PS3_BUTTON_B 1 -#define GAMEPAD_PS3_BUTTON_X 3 -#define GAMEPAD_PS3_BUTTON_Y 4 -#define GAMEPAD_PS3_BUTTON_R1 7 -#define GAMEPAD_PS3_BUTTON_R2 5 +// PS3 USB Controller Buttons +#define GAMEPAD_PS3_BUTTON_TRIANGLE 0 +#define GAMEPAD_PS3_BUTTON_CIRCLE 1 +#define GAMEPAD_PS3_BUTTON_CROSS 2 +#define GAMEPAD_PS3_BUTTON_SQUARE 3 #define GAMEPAD_PS3_BUTTON_L1 6 -#define GAMEPAD_PS3_BUTTON_L2 8 +#define GAMEPAD_PS3_BUTTON_R1 7 +#define GAMEPAD_PS3_BUTTON_L2 4 +#define GAMEPAD_PS3_BUTTON_R2 5 +#define GAMEPAD_PS3_BUTTON_START 8 #define GAMEPAD_PS3_BUTTON_SELECT 9 -#define GAMEPAD_PS3_BUTTON_START 10 +#define GAMEPAD_PS3_BUTTON_UP 24 +#define GAMEPAD_PS3_BUTTON_RIGHT 25 +#define GAMEPAD_PS3_BUTTON_DOWN 26 +#define GAMEPAD_PS3_BUTTON_LEFT 27 +#define GAMEPAD_PS3_BUTTON_PS 12 -// TODO: Add PS3 d-pad axis +// PS3 USB Controller Axis +#define GAMEPAD_PS3_AXIS_LEFT_X 0 +#define GAMEPAD_PS3_AXIS_LEFT_Y 1 +#define GAMEPAD_PS3_AXIS_RIGHT_X 2 +#define GAMEPAD_PS3_AXIS_RIGHT_Y 5 +#define GAMEPAD_PS3_AXIS_L2 3 // 1.0(not pressed) --> -1.0(completely pressed) +#define GAMEPAD_PS3_AXIS_R2 4 // 1.0(not pressed) --> -1.0(completely pressed) // Xbox360 USB Controller Buttons #define GAMEPAD_XBOX_BUTTON_A 0 @@ -221,22 +232,27 @@ #define GAMEPAD_XBOX_BUTTON_RIGHT 11 #define GAMEPAD_XBOX_BUTTON_DOWN 12 #define GAMEPAD_XBOX_BUTTON_LEFT 13 +#define GAMEPAD_XBOX_BUTTON_HOME 9 +// Xbox360 USB Controller Axis #define GAMEPAD_XBOX_AXIS_LEFT_X 0 #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 +#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 +#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 +#define GAMEPAD_XBOX_AXIS_LT 4 // -1.0(not pressed) --> 1.0(completely pressed) +#define GAMEPAD_XBOX_AXIS_RT 5 // -1.0(not pressed) --> 1.0(completely pressed) +/* +// NOTE: For Raspberry Pi, axis must be reconfigured #if defined(PLATFORM_RPI) - #define GAMEPAD_XBOX_AXIS_DPAD_X 7 - #define GAMEPAD_XBOX_AXIS_DPAD_Y 6 + #define GAMEPAD_XBOX_AXIS_LEFT_X 7 + #define GAMEPAD_XBOX_AXIS_LEFT_Y 6 #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 #define GAMEPAD_XBOX_AXIS_LT 2 #define GAMEPAD_XBOX_AXIS_RT 5 -#else - #define GAMEPAD_XBOX_AXIS_RIGHT_X 4 - #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 - #define GAMEPAD_XBOX_AXIS_LT_RT 2 #endif +*/ // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. @@ -533,6 +549,12 @@ typedef enum { COMPRESSED_ASTC_8x8_RGBA // 2 bpp } TextureFormat; +// Texture parameters: filter mode +typedef enum { FILTER_POINT = 0, FILTER_BILINEAR, FILTER_TRILINEAR } TextureFilterMode; + +// Texture parameters: wrap mode +typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; + // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; @@ -663,6 +685,7 @@ RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gam RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed +RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed #endif RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once @@ -752,6 +775,7 @@ RLAPI void UnloadTexture(Texture2D texture); RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image +RLAPI void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data 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 @@ -773,7 +797,8 @@ 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 GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture -RLAPI void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data +RLAPI void SetTextureFilter(Texture2D texture, int filterMode); +RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); 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 From 43fd9ffe08025a82b79ce41c22c6ae82feb2c9aa Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 29 Oct 2016 22:16:54 +0200 Subject: [PATCH 11/32] Tweak to avoid warnings --- src/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.c b/src/core.c index 8646bf8f1..b8574f0a5 100644 --- a/src/core.c +++ b/src/core.c @@ -208,8 +208,8 @@ static int currentMouseWheelY = 0; // Registers current mouse wheel var // Register gamepads states static bool gamepadReady[MAX_GAMEPADS] = { false }; // Flag to know if gamepad is ready static float gamepadAxisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state -static char previousGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS] = { 0 }; -static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS] = { 0 }; +static char previousGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state +static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state // Keyboard configuration static int exitKey = KEY_ESCAPE; // Default exit key (ESC) From 988d39029f9c562ae044e4b5b0d129c367ffbe16 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 29 Oct 2016 22:17:19 +0200 Subject: [PATCH 12/32] Support textures filtering --- src/raylib.h | 15 +++++++-- src/rlgl.c | 88 ++++++++++++++++++++++++++++++-------------------- src/rlgl.h | 35 +++++++++++++++++--- src/textures.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 178 insertions(+), 48 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 491923dcc..b0ee96bb5 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -550,7 +550,16 @@ typedef enum { } TextureFormat; // Texture parameters: filter mode -typedef enum { FILTER_POINT = 0, FILTER_BILINEAR, FILTER_TRILINEAR } TextureFilterMode; +// NOTE 1: Filtering considers mipmaps if available in the texture +// NOTE 2: Filter is accordingly set for minification and magnification +typedef enum { + FILTER_POINT = 0, // No filter, just pixel aproximation + FILTER_BILINEAR, // Linear filtering + FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x +} TextureFilterMode; // Texture parameters: wrap mode typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; @@ -797,8 +806,8 @@ 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 GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture -RLAPI void SetTextureFilter(Texture2D texture, int filterMode); -RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); +RLAPI void SetTextureFilter(Texture2D texture, int filterMode); // Set texture scaling filter mode +RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); // Set texture wrapping mode 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 diff --git a/src/rlgl.c b/src/rlgl.c index 0a7e35836..492ca3a62 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -140,6 +140,14 @@ #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 #endif +#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#endif + #if defined(GRAPHICS_API_OPENGL_11) #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 @@ -283,14 +291,21 @@ static Shader standardShader; // Shader with support for lighting static Shader currentShader; // Shader to be used on rendering (by default, defaultShader) static bool standardShaderLoaded = false; // Flag to track if standard shader has been loaded -// Flags for supported extensions +// Extension supported flag: VAO static bool vaoSupported = false; // VAO support (OpenGL ES2 could not support VAO extension) -// Compressed textures support flags +// Extension supported flag: Compressed textures static bool texCompETC1Supported = false; // ETC1 texture compression support static bool texCompETC2Supported = false; // ETC2/EAC texture compression support static bool texCompPVRTSupported = false; // PVR texture compression support static bool texCompASTCSupported = false; // ASTC texture compression support + +// Extension supported flag: Anisotropic filtering +static bool texAnisotropicFilterSupported = false; // Anisotropic texture filtering support +static float maxAnisotropicLevel = 0.0f; // Maximum anisotropy level supported (minimum is 2.0f) + +// Extension supported flag: Clamp mirror wrap mode +static bool texClampMirrorSupported = false; // Clamp mirror wrap mode supported #endif #if defined(RLGL_OCULUS_SUPPORT) @@ -871,45 +886,34 @@ void rlDisableTexture(void) #endif } -// Set texture parameters -// TODO: Review this function to choose right filter/wrap value +// Set texture parameters (wrap mode/filter mode) void rlTextureParameters(unsigned int id, int param, int value) { -/* -// TextureWrapMode -#define GL_REPEAT 0x2901 -#define GL_CLAMP_TO_EDGE 0x812F - -// TextureMagFilter -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 - -// TextureMinFilter -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -*/ - - int glValue = 0; - glBindTexture(GL_TEXTURE_2D, id); - - switch (value) + + switch (param) { - case FILTER_POINT: glValue = GL_NEAREST; break; - case FILTER_BILINEAR: glValue = GL_LINEAR; break; - case FILTER_TRILINEAR: glValue = GL_LINEAR; break; - //case WRAP_REPEAT: glValue = GL_REPEAT; break; - //case WRAP_CLAMP: glValue = GL_CLAMP_TO_EDGE; break; - //case WRAP_MIRROR: glValue = GL_NEAREST; break; + case RL_TEXTURE_WRAP_S: + case RL_TEXTURE_WRAP_T: + { + if ((value == RL_WRAP_CLAMP_MIRROR) && !texClampMirrorSupported) TraceLog(WARNING, "Clamp mirror wrap mode not supported"); + else glTexParameteri(GL_TEXTURE_2D, param, value); + } break; + case RL_TEXTURE_MAG_FILTER: + case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break; + case RL_TEXTURE_ANISOTROPIC_FILTER: + { + if (value <= maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value); + else if (maxAnisotropicLevel > 0.0f) + { + TraceLog(WARNING, "[TEX ID %i] Maximum anisotropic filter level supported is %iX", id, maxAnisotropicLevel); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value); + } + else TraceLog(WARNING, "Anisotropic filtering not supported"); + } break; default: break; } - glTexParameteri(GL_TEXTURE_2D, param, glValue); - glBindTexture(GL_TEXTURE_2D, 0); } @@ -1166,7 +1170,7 @@ void rlglInit(int width, int height) // Check NPOT textures support // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) npotSupported = true; -#endif +#endif // DDS texture compression support if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || @@ -1185,6 +1189,16 @@ void rlglInit(int width, int height) // ASTC texture compression support if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) texCompASTCSupported = true; + + // Anisotropic texture filter support + if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) + { + texAnisotropicFilterSupported = true; + glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + } + + // Clamp mirror wrap mode supported + if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; } #ifdef _MSC_VER @@ -1204,6 +1218,9 @@ void rlglInit(int width, int height) if (texCompETC2Supported) TraceLog(INFO, "[EXTENSION] ETC2/EAC compressed textures supported"); if (texCompPVRTSupported) TraceLog(INFO, "[EXTENSION] PVRT compressed textures supported"); if (texCompASTCSupported) TraceLog(INFO, "[EXTENSION] ASTC compressed textures supported"); + + if (texAnisotropicFilterSupported) TraceLog(INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel); + if (texClampMirrorSupported) TraceLog(INFO, "[EXTENSION] Clamp mirror wrap texture mode supported"); // Initialize buffers, default shaders and default textures //---------------------------------------------------------- @@ -1729,6 +1746,7 @@ void rlglGenerateMipmaps(Texture2D texture) #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture.id); diff --git a/src/rlgl.h b/src/rlgl.h index b6679ef68..9be73f363 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -91,10 +91,22 @@ #endif // Texture parameters (equivalent to OpenGL defines) -#define RL_TEXTURE_MAG_FILTER 0x2800 -#define RL_TEXTURE_MIN_FILTER 0x2801 -#define RL_TEXTURE_WRAP_S 0x2802 -#define RL_TEXTURE_WRAP_T 0x2803 +#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S +#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T +#define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER +#define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER +#define RL_TEXTURE_ANISOTROPIC_FILTER 0x3000 // Anisotropic filter (custom identifier) + +#define RL_FILTER_NEAREST 0x2600 // GL_NEAREST +#define RL_FILTER_LINEAR 0x2601 // GL_LINEAR +#define RL_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST +#define RL_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR +#define RL_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST +#define RL_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR + +#define RL_WRAP_REPEAT 0x2901 // GL_REPEAT +#define RL_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE +#define RL_WRAP_CLAMP_MIRROR 0x8742 // GL_MIRROR_CLAMP_EXT //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -242,6 +254,21 @@ typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode; // Light types typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; + + // Texture parameters: filter mode + // NOTE 1: Filtering considers mipmaps if available in the texture + // NOTE 2: Filter is accordingly set for minification and magnification + typedef enum { + FILTER_POINT = 0, // No filter, just pixel aproximation + FILTER_BILINEAR, // Linear filtering + FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x + } TextureFilterMode; + + // Texture parameters: wrap mode + typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; diff --git a/src/textures.c b/src/textures.c index 867e565d5..729756a54 100644 --- a/src/textures.c +++ b/src/textures.c @@ -442,18 +442,94 @@ void UnloadRenderTexture(RenderTexture2D target) if (target.id != 0) rlDeleteRenderTextures(target); } -// Set texture scale filter +// Set texture scaling filter mode void SetTextureFilter(Texture2D texture, int filterMode) { - rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, filterMode); - rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, filterMode); + switch (filterMode) + { + case FILTER_POINT: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST); + + // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); + } + else + { + // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); + } + } break; + case FILTER_BILINEAR: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps) + // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST); + + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + else + { + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + } break; + case FILTER_TRILINEAR: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR); + + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + else + { + TraceLog(WARNING, "[TEX 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); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + } break; + case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break; + case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break; + case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break; + default: break; + } } -// Set texture wrap mode +// Set texture wrapping mode void SetTextureWrap(Texture2D texture, int wrapMode) { - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, wrapMode); - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, wrapMode); + switch (wrapMode) + { + case WRAP_REPEAT: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT); + } break; + case WRAP_CLAMP: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP); + } break; + case WRAP_MIRROR: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR); + } break; + default: break; + } } // Get pixel data from image in the form of Color struct array From 836d3341a52f1580ce5ea1b2d691b1988b109b9f Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 31 Oct 2016 13:54:37 +0100 Subject: [PATCH 13/32] Renamed OpenAL32 dll library --- .../win32/{libOpenAL32.dll.a => libOpenAL32dll.a} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename src/external/openal_soft/lib/win32/{libOpenAL32.dll.a => libOpenAL32dll.a} (100%) diff --git a/src/external/openal_soft/lib/win32/libOpenAL32.dll.a b/src/external/openal_soft/lib/win32/libOpenAL32dll.a similarity index 100% rename from src/external/openal_soft/lib/win32/libOpenAL32.dll.a rename to src/external/openal_soft/lib/win32/libOpenAL32dll.a From 16101ce3d8c601447f935056b09a36ea3afefe7d Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 31 Oct 2016 13:56:57 +0100 Subject: [PATCH 14/32] Reorganize defines check --- src/core.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/core.c b/src/core.c index b8574f0a5..9bb7b8cf1 100644 --- a/src/core.c +++ b/src/core.c @@ -198,6 +198,7 @@ static Matrix downscaleView; // Matrix to downscale view (in case #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) static const char *windowTitle; // Window text title... static bool cursorOnScreen = false; // Tracks if cursor is inside client area +static bool cursorHidden = false; // Track if cursor is hidden // Register mouse states static char previousMouseState[3] = { 0 }; // Registers previous mouse button state @@ -213,8 +214,6 @@ static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Curre // Keyboard configuration static int exitKey = KEY_ESCAPE; // Default exit key (ESC) - -static bool cursorHidden; // Track if cursor is hidden #endif // Register keyboard states @@ -1155,15 +1154,16 @@ void SetExitKey(int key) #endif } -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) // Detect if a gamepad is available bool IsGamepadAvailable(int gamepad) { bool result = false; - + +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) result = true; +#endif return result; } @@ -1183,11 +1183,10 @@ const char *GetGamepadName(int gamepad) float GetGamepadAxisMovement(int gamepad, int axis) { float value = 0; - - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (axis < MAX_GAMEPAD_AXIS)) - { - value = gamepadAxisState[gamepad][axis]; - } + +#if !defined(PLATFORM_ANDROID) + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (axis < MAX_GAMEPAD_AXIS)) value = gamepadAxisState[gamepad][axis]; +#endif return value; } @@ -1196,10 +1195,12 @@ float GetGamepadAxisMovement(int gamepad, int axis) bool IsGamepadButtonPressed(int gamepad, int button) { bool pressed = false; - + +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && (currentGamepadState[gamepad][button] == 1)) pressed = true; +#endif return pressed; } @@ -1209,8 +1210,10 @@ bool IsGamepadButtonDown(int gamepad, int button) { bool result = false; +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] == 1)) result = true; +#endif return result; } @@ -1220,9 +1223,11 @@ bool IsGamepadButtonReleased(int gamepad, int button) { bool released = false; +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && (currentGamepadState[gamepad][button] == 0)) released = true; +#endif return released; } @@ -1232,8 +1237,10 @@ bool IsGamepadButtonUp(int gamepad, int button) { bool result = false; +#if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] == 0)) result = true; +#endif return result; } @@ -1244,9 +1251,6 @@ int GetGamepadButtonPressed(void) return lastGamepadButtonPressed; } -#endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) - - // Detect if a mouse button has been pressed once bool IsMouseButtonPressed(int button) { From cc917fbac6e7007fdb744afaf8f0879c984d95af Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 31 Oct 2016 15:38:15 +0100 Subject: [PATCH 15/32] Improve SpriteFont support LoadSpriteFontTTF() - TTF font loading with custom parameters --- src/raylib.h | 3 +-- src/text.c | 74 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index b0ee96bb5..4996bb2bf 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -686,7 +686,6 @@ RLAPI bool IsKeyUp(int key); // Detect if a key RLAPI int GetKeyPressed(void); // Get latest key pressed RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis @@ -695,7 +694,6 @@ RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gam RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed -#endif RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed @@ -821,6 +819,7 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest //------------------------------------------------------------------------------------ RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory +RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load a SpriteFont from TTF font with parameters RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) diff --git a/src/text.c b/src/text.c index 5e978823b..7707db7c6 100644 --- a/src/text.c +++ b/src/text.c @@ -33,6 +33,7 @@ #include "utils.h" // Required for: GetExtension() // Following libs are used on LoadTTF() +//#define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION #include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() @@ -268,20 +269,35 @@ SpriteFont LoadSpriteFont(const char *fileName) TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName); spriteFont = GetDefaultFont(); } + else SetTextureFilter(spriteFont.texture, FILTER_BILINEAR); return spriteFont; } -// Generate SpriteFont from TTF file +// Load SpriteFont from TTF file with custom parameters // NOTE: You can pass an array with desired characters, those characters should be available in the font // if array is NULL, default char set is selected 32..126 -SpriteFont GenSpriteFont(const char *fileName, int fontSize, int *fontChars) +SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars) { SpriteFont spriteFont = { 0 }; if (strcmp(GetExtension(fileName),"ttf") == 0) { - spriteFont = LoadTTF(fileName, fontSize, FONT_FIRST_CHAR, DEFAULT_TTF_NUMCHARS); + int firstChar = 0; + int totalChars = 0; + + if ((fontChars == NULL) || (numChars == 0)) + { + firstChar = 32; // Default first character: SPACE[32] + totalChars = 95; // Default charset [32..126] + } + else + { + firstChar = fontChars[0]; + totalChars = numChars; + } + + spriteFont = LoadTTF(fileName, fontSize, firstChar, totalChars); } if (spriteFont.texture.id == 0) @@ -522,7 +538,7 @@ void DrawFPS(int posX, int posY) // Module specific Functions Definition //---------------------------------------------------------------------------------- -// Load a Image font file (XNA style) +// Load an Image font file (XNA style) static SpriteFont LoadImageFont(Image image, Color key, int firstChar) { #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) @@ -595,15 +611,24 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) xPosToRead = charSpacing; } - free(pixels); - TraceLog(DEBUG, "SpriteFont 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; + + // Create a new image with the processed color data (key color replaced by BLANK) + Image fontClear = LoadImageEx(pixels, image.width, image.height); + + free(pixels); // Free pixels array memory // Create spritefont with all data parsed from image SpriteFont spriteFont = { 0 }; - spriteFont.texture = LoadTextureFromImage(image); // Convert loaded image to OpenGL texture + spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture spriteFont.numChars = index; + + UnloadImage(fontClear); // Unload processed image once converted to texture // We got tempCharValues and tempCharsRecs populated with chars data // Now we move temp data to sized charValues and charRecs arrays @@ -900,12 +925,15 @@ static SpriteFont LoadBMFont(const char *fileName) // TODO: Review texture packing method and generation (use oversampling) static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int numChars) { - // NOTE: Generated font uses some hardcoded values - #define FONT_TEXTURE_WIDTH 512 // Font texture width - #define FONT_TEXTURE_HEIGHT 512 // Font texture height + // NOTE: Font texture size is predicted (being as much conservative as possible) + // Predictive method consist of supposing same number of chars by line-column (sqrtf) + // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... + int textureSize = GetNextPOT(ceil((float)fontSize*3/4)*ceil(sqrtf((float)numChars))); + + TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25); - unsigned char *dataBitmap = (unsigned char *)malloc(FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*sizeof(unsigned char)); // One channel bitmap returned! + unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*numChars); SpriteFont font = { 0 }; @@ -914,40 +942,44 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int if (ttfFile == NULL) { - TraceLog(WARNING, "[%s] FNT file could not be opened", fileName); + TraceLog(WARNING, "[%s] TTF file could not be opened", fileName); return font; } fread(ttfBuffer, 1, 1<<25, ttfFile); // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... - stbtt_BakeFontBitmap(ttfBuffer,0, fontSize, dataBitmap, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, firstChar, numChars, charData); + // TODO: Replace this function by a proper packing method and support random chars order + int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, firstChar, numChars, charData); + //if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); + if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font"); + free(ttfBuffer); // Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA - unsigned char *dataGrayAlpha = (unsigned char *)malloc(FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*sizeof(unsigned char)*2); // Two channels - int k = 0; + unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels - for (int i = 0; i < FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT; i++) + for (int i = 0, k = 0; i < textureSize*textureSize; i++, k += 2) { dataGrayAlpha[k] = 255; dataGrayAlpha[k + 1] = dataBitmap[i]; - - k += 2; } free(dataBitmap); // Sprite font generation from TTF extracted data Image image; - image.width = FONT_TEXTURE_WIDTH; - image.height = FONT_TEXTURE_HEIGHT; + image.width = textureSize; + image.height = textureSize; image.mipmaps = 1; image.format = UNCOMPRESSED_GRAY_ALPHA; image.data = dataGrayAlpha; - + font.texture = LoadTextureFromImage(image); + + //WritePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2); + UnloadImage(image); // Unloads dataGrayAlpha font.size = fontSize; From 673dcf94364d37f3d52285ac27c88707ae567872 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 31 Oct 2016 20:39:03 +0100 Subject: [PATCH 16/32] Comments tweaks --- src/core.c | 2 +- src/models.c | 2 +- src/rlgl.c | 2 +- src/shapes.c | 15 +++++++-------- src/textures.c | 4 ++-- src/utils.c | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/core.c b/src/core.c index 9bb7b8cf1..8850eefa1 100644 --- a/src/core.c +++ b/src/core.c @@ -22,7 +22,7 @@ * * RL_LOAD_DEFAULT_FONT - Use external module functions to load default raylib font (module: text) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 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. diff --git a/src/models.c b/src/models.c index 55ac78930..c0f043877 100644 --- a/src/models.c +++ b/src/models.c @@ -4,7 +4,7 @@ * * Basic functions to draw 3d shapes and load/draw 3d models (.OBJ) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 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. diff --git a/src/rlgl.c b/src/rlgl.c index 492ca3a62..e2804e9cc 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -35,7 +35,7 @@ #include // Required for: atan2() #ifndef RLGL_STANDALONE - #include "raymath.h" // Required for Vector3 and Matrix functions + #include "raymath.h" // Required for: Vector3 and Matrix functions #endif #if defined(GRAPHICS_API_OPENGL_11) diff --git a/src/shapes.c b/src/shapes.c index 62076b2c8..79cf567a4 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -4,7 +4,7 @@ * * Basic functions to draw 2d Shapes and check collisions * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 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,9 +25,8 @@ #include "raylib.h" -#include // Required for abs() function -#include // Math related functions, sin() and cos() used on DrawCircle* - // sqrt() and pow() and abs() used on CheckCollision* +#include // Required for: abs() +#include // Required for: sinf(), cosf(), sqrtf() #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 @@ -331,8 +330,8 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(0, 0); - rlVertex2f(sin(DEG2RAD*i)*radius, cos(DEG2RAD*i)*radius); - rlVertex2f(sin(DEG2RAD*(i + 360/sides))*radius, cos(DEG2RAD*(i + 360/sides))*radius); + rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius); + rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius); } rlEnd(); rlPopMatrix(); @@ -434,7 +433,7 @@ bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, floa float dx = center2.x - center1.x; // X distance between centers float dy = center2.y - center1.y; // Y distance between centers - float distance = sqrt(dx*dx + dy*dy); // Distance between centers + float distance = sqrtf(dx*dx + dy*dy); // Distance between centers if (distance <= (radius1 + radius2)) collision = true; @@ -457,7 +456,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) if (dx <= (rec.width/2)) { return true; } if (dy <= (rec.height/2)) { return true; } - float cornerDistanceSq = pow(dx - rec.width/2, 2) + pow(dy - rec.height/2, 2); + float cornerDistanceSq = (dx - rec.width/2)*(dx - rec.width/2) + (dy - rec.height/2)*(dy - rec.height/2); return (cornerDistanceSq <= (radius*radius)); } diff --git a/src/textures.c b/src/textures.c index 729756a54..5354a74fe 100644 --- a/src/textures.c +++ b/src/textures.c @@ -8,7 +8,7 @@ * stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) * NOTE: stb_image has been slightly modified, original library: https://github.com/nothings/stb * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 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. @@ -1241,7 +1241,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing // NOTE: GetTextureData() not available in OpenGL ES Image imFont = GetTextureData(font.texture); - ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Required for color tint + ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Convert to 32 bit for color tint ImageColorTint(&imFont, tint); // Apply color tint to font Color *fontPixels = GetImageData(imFont); diff --git a/src/utils.c b/src/utils.c index 36b06f0f4..b96e2c70a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -8,7 +8,7 @@ * tinfl - zlib DEFLATE algorithm decompression lib * stb_image_write - PNG writting functions * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 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. From 3393fda384479b237519c70a1cedeb0e5dad369c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 31 Oct 2016 20:39:30 +0100 Subject: [PATCH 17/32] Improve TTF loading --- src/text.c | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/text.c b/src/text.c index 7707db7c6..f56f588e4 100644 --- a/src/text.c +++ b/src/text.c @@ -4,7 +4,7 @@ * * Basic functions to load SpriteFonts and draw Text * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 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. @@ -30,7 +30,7 @@ #include // Required for: va_list, va_start(), vfprintf(), va_end() #include // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets() -#include "utils.h" // Required for: GetExtension() +#include "utils.h" // Required for: GetExtension(), GetNextPOT() // Following libs are used on LoadTTF() //#define STBTT_STATIC @@ -72,9 +72,7 @@ static SpriteFont defaultFont; // Default font provided by raylib static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) - -// Generate a sprite font image from TTF data -static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int numChars); +static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load spritefont from TTF data extern void LoadDefaultFont(void); extern void UnloadDefaultFont(void); @@ -255,7 +253,7 @@ SpriteFont LoadSpriteFont(const char *fileName) // Check file extension if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); - else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadTTF(fileName, DEFAULT_TTF_FONTSIZE, FONT_FIRST_CHAR, DEFAULT_TTF_NUMCHARS); + else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadSpriteFontTTF(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); else if (strcmp(GetExtension(fileName),"fnt") == 0) spriteFont = LoadBMFont(fileName); else { @@ -283,21 +281,17 @@ SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, i if (strcmp(GetExtension(fileName),"ttf") == 0) { - int firstChar = 0; - int totalChars = 0; - if ((fontChars == NULL) || (numChars == 0)) { - firstChar = 32; // Default first character: SPACE[32] - totalChars = 95; // Default charset [32..126] + int totalChars = 95; // Default charset [32..126] + + int *defaultFontChars = (int *)malloc(totalChars*sizeof(int)); + + for (int i = 0; i < totalChars; i++) defaultFontChars[i] = i + 32; // Default first character: SPACE[32] + + spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars); } - else - { - firstChar = fontChars[0]; - totalChars = numChars; - } - - spriteFont = LoadTTF(fileName, fontSize, firstChar, totalChars); + else spriteFont = LoadTTF(fileName, fontSize, numChars, fontChars); } if (spriteFont.texture.id == 0) @@ -325,7 +319,6 @@ void UnloadSpriteFont(SpriteFont spriteFont) } } - // Draw text (using default font) // NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used // NOTE: chars spacing is proportional to fontSize @@ -549,8 +542,8 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) int x = 0; int y = 0; - // Default number of characters expected supported - #define MAX_FONTCHARS 128 + // Default number of characters supported + #define MAX_FONTCHARS 256 // We allocate a temporal arrays for chars data measures, // once we get the actual number of chars, we copy data to a sized arrays @@ -923,7 +916,7 @@ static SpriteFont LoadBMFont(const char *fileName) // Generate a sprite font from TTF file data (font size required) // TODO: Review texture packing method and generation (use oversampling) -static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int numChars) +static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars) { // NOTE: Font texture size is predicted (being as much conservative as possible) // Predictive method consist of supposing same number of chars by line-column (sqrtf) @@ -947,10 +940,13 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int } fread(ttfBuffer, 1, 1<<25, ttfFile); + + if (fontChars[0] != 32) TraceLog(WARNING, "TTF spritefont loading: first character is not SPACE(32) character"); // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... - // TODO: Replace this function by a proper packing method and support random chars order - int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, firstChar, numChars, charData); + // TODO: Replace this function by a proper packing method and support random chars order, + // we already receive a list (fontChars) with the ordered expected characters + int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], numChars, charData); //if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font"); @@ -991,7 +987,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int for (int i = 0; i < font.numChars; i++) { - font.charValues[i] = i + firstChar; + font.charValues[i] = fontChars[i]; font.charRecs[i].x = (int)charData[i].x0; font.charRecs[i].y = (int)charData[i].y0; From 6d3b11ef9124c9d938d9ecd2b341837bd5ed5dc1 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 1 Nov 2016 00:58:21 +0100 Subject: [PATCH 18/32] Support unordered charset, neither fixed first char Still requires some testing... --- src/text.c | 79 +++++++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/src/text.c b/src/text.c index f56f588e4..23041603d 100644 --- a/src/text.c +++ b/src/text.c @@ -44,7 +44,6 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FONT_FIRST_CHAR 32 // NOTE: Expected first char for a sprite font #define MAX_FORMATTEXT_LENGTH 64 #define MAX_SUBTEXT_LENGTH 64 @@ -69,6 +68,8 @@ static SpriteFont defaultFont; // Default font provided by raylib //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- +static int GetCharIndex(SpriteFont font, int letter); + static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) @@ -197,7 +198,7 @@ extern void LoadDefaultFont(void) for (int i = 0; i < defaultFont.numChars; i++) { - defaultFont.charValues[i] = FONT_FIRST_CHAR + i; // First char is 32 + defaultFont.charValues[i] = 32 + i; // First char is 32 defaultFont.charRecs[i].x = currentPosX; defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); @@ -248,6 +249,7 @@ SpriteFont LoadSpriteFont(const char *fileName) // Default hardcoded values for ttf file loading #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs + #define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont SpriteFont spriteFont = { 0 }; @@ -258,7 +260,7 @@ SpriteFont LoadSpriteFont(const char *fileName) else { Image image = LoadImage(fileName); - if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, FONT_FIRST_CHAR); + if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); UnloadImage(image); } @@ -267,7 +269,7 @@ SpriteFont LoadSpriteFont(const char *fileName) TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName); spriteFont = GetDefaultFont(); } - else SetTextureFilter(spriteFont.texture, FILTER_BILINEAR); + else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance) return spriteFont; } @@ -356,22 +358,18 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float for (int i = 0; i < length; i++) { - // TODO: Right now we are supposing characters that follow a continous order and start at FONT_FIRST_CHAR, - // this sytem can be improved to support any characters order and init value... - // An intermediate table could be created to link char values with predefined char position index in chars rectangle array - if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! { // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) letter = (unsigned char)text[i + 1]; - rec = spriteFont.charRecs[letter - FONT_FIRST_CHAR]; + rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)letter)]; i++; } else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! { // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) letter = (unsigned char)text[i + 1]; - rec = spriteFont.charRecs[letter - FONT_FIRST_CHAR + 64]; + rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)letter + 64)]; i++; } else @@ -383,17 +381,19 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float textOffsetX = 0; rec.x = -1; } - else rec = spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR]; + else rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)text[i])]; } if (rec.x >= 0) { - DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x*scaleFactor, - position.y + textOffsetY + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].y*scaleFactor, + int index = GetCharIndex(spriteFont, (int)text[i]); + + DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor, + position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor, rec.width*scaleFactor, rec.height*scaleFactor} , (Vector2){ 0, 0 }, 0.0f, tint); - if (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR] == 0) textOffsetX += (rec.width*scaleFactor + spacing); - else textOffsetX += (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR]*scaleFactor + spacing); + if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (rec.width*scaleFactor + spacing); + else textOffsetX += (spriteFont.charAdvanceX[index]*scaleFactor + spacing); } } } @@ -473,8 +473,10 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int if (text[i] != '\n') { - if (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR] != 0) textWidth += spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR]; - else textWidth += (spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR].width + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x); + int index = GetCharIndex(spriteFont, (int)text[i]); + + if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index]; + else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x); } else { @@ -531,6 +533,27 @@ void DrawFPS(int posX, int posY) // Module specific Functions Definition //---------------------------------------------------------------------------------- +static int GetCharIndex(SpriteFont font, int letter) +{ +//#define UNORDERED_CHARSET +#if defined(UNORDERED_CHARSET) + int index = 0; + + for (int i = 0; i < font.numChars; i++) + { + if (font.charValues[i] == letter) + { + index = i; + break; + } + } + + return index; +#else + return (letter - 32); +#endif +} + // Load an Image font file (XNA style) static SpriteFont LoadImageFont(Image image, Color key, int firstChar) { @@ -857,6 +880,7 @@ static SpriteFont LoadBMFont(const char *fileName) if (imFont.format == UNCOMPRESSED_GRAYSCALE) ImageAlphaMask(&imFont, imFont); font.texture = LoadTextureFromImage(imFont); + font.size = fontSize; font.numChars = numChars; font.charValues = (int *)malloc(numChars*sizeof(int)); @@ -870,30 +894,12 @@ static SpriteFont LoadBMFont(const char *fileName) int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; - bool unorderedChars = false; - int firstChar = 32; - for (int i = 0; i < numChars; i++) { fgets(buffer, MAX_BUFFER_SIZE, fntFile); sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); - if ((i == 0) && (charId != FONT_FIRST_CHAR)) - { - TraceLog(WARNING, "BMFont not supported: expected SPACE(32) as first character, falling back to default font"); - firstChar = charId; - break; - } - else if ((i < (126 - FONT_FIRST_CHAR)) && (i != (charId - FONT_FIRST_CHAR))) - { - // NOTE: We expect the first 95 chars (32..126) to be ordered for quick drawing access, - // characters above are stored and we look for them (search algorythm) when drawing - TraceLog(WARNING, "BMFont not supported: unordered chars data, falling back to default font"); - unorderedChars = true; - break; - } - // Save data properly in sprite font font.charValues[i] = charId; font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight }; @@ -903,8 +909,7 @@ static SpriteFont LoadBMFont(const char *fileName) fclose(fntFile); - // NOTE: Font data could be not ordered by charId: 32,33,34,35... raylib does not support unordered BMFonts - if ((firstChar != FONT_FIRST_CHAR) || (unorderedChars) || (font.texture.id == 0)) + if (font.texture.id == 0) { UnloadSpriteFont(font); font = GetDefaultFont(); From 64f67f6e9f414a54dfc3fb519b892ecd5517f2cf Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 1 Nov 2016 14:39:57 +0100 Subject: [PATCH 19/32] Improved gamepad support new function: GetGamepadAxisCount() new function: IsGamepadName() --- src/core.c | 50 +++++++++++++++++++++++++++++++++++++++----------- src/raylib.h | 4 +++- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/core.c b/src/core.c index 8850eefa1..3bade07bf 100644 --- a/src/core.c +++ b/src/core.c @@ -58,12 +58,12 @@ #endif #include // Standard input / output lib -#include // Declares malloc() and free() for memory management, rand(), atexit() -#include // Required for typedef unsigned long long int uint64_t, used by hi-res timer -#include // Useful to initialize random seed - Android/RPI hi-res timer (NOTE: Linux only!) -#include // Math related functions, tan() used to set perspective -#include // String function definitions, memset() -#include // Macros for reporting and retrieving error conditions through error codes +#include // Required for: malloc(), free(), rand(), atexit() +#include // Required for: typedef unsigned long long int uint64_t, used by hi-res timer +#include // Required for: time() - Android/RPI hi-res timer (NOTE: Linux only!) +#include // Required for: tan() [Used in Begin3dMode() to set perspective] +#include // Required for: strcmp() +//#include // Macros for reporting and retrieving error conditions through error codes #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 @@ -222,6 +222,7 @@ static char currentKeyState[512] = { 0 }; // Registers current frame key state static int lastKeyPressed = -1; // Register last key pressed static int lastGamepadButtonPressed = -1; // Register last gamepad button pressed +static int gamepadAxisCount = 0; // Register number of available gamepad axis static Vector2 mousePosition; // Mouse position on screen static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen @@ -1168,17 +1169,36 @@ bool IsGamepadAvailable(int gamepad) return result; } +// Check gamepad name (if available) +bool IsGamepadName(int gamepad, const char *name) +{ + bool result = false; + const char *gamepadName = NULL; + + if (gamepadReady[gamepad]) gamepadName = GetGamepadName(gamepad); + + if ((name != NULL) && (gamepadName != NULL)) result = (strcmp(name, gamepadName) == 0); + + return result; +} + // Return gamepad internal name id const char *GetGamepadName(int gamepad) { #if defined(PLATFORM_DESKTOP) - if (glfwJoystickPresent(gamepad) == 1) return glfwGetJoystickName(gamepad); + if (gamepadReady[gamepad]) return glfwGetJoystickName(gamepad); else return NULL; #else return NULL; #endif } +// Return gamepad axis count +int GetGamepadAxisCount(int gamepad) +{ + return gamepadAxisCount; +} + // Return axis movement vector for a gamepad float GetGamepadAxisMovement(int gamepad, int axis) { @@ -1921,6 +1941,7 @@ static void PollInputEvents(void) // Reset last gamepad button pressed registered lastGamepadButtonPressed = -1; + gamepadAxisCount = 0; #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -1943,13 +1964,19 @@ static void PollInputEvents(void) previousMouseWheelY = currentMouseWheelY; currentMouseWheelY = 0; + // Check if gamepads are ready + // NOTE: We do it here in case of disconection + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (glfwJoystickPresent(i)) gamepadReady[i] = true; + else gamepadReady[i] = false; + } + // Register gamepads buttons events for (int i = 0; i < MAX_GAMEPADS; i++) { - if (glfwJoystickPresent(i)) // Check if gamepad is available + if (gamepadReady[i]) // Check if gamepad is available { - gamepadReady[i] = true; - // Register previous gamepad states for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k]; @@ -1980,8 +2007,9 @@ static void PollInputEvents(void) { gamepadAxisState[i][k] = axes[k]; } + + gamepadAxisCount = axisCount; } - else gamepadReady[i] = false; } glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events! diff --git a/src/raylib.h b/src/raylib.h index 4996bb2bf..58037770f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -687,13 +687,15 @@ RLAPI int GetKeyPressed(void); // Get latest key RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available +RLAPI bool IsGamepadName(int gamepad, const char *name); // Check gamepad name (if available) RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id -RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed +RLAPI int GetGamepadAxisCount(int gamepad); // Return gamepad axis count for a gamepad +RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed From f16f39e8aaf0ee95a31600e549c0221d1ce46fdd Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 2 Nov 2016 00:50:08 +0100 Subject: [PATCH 20/32] code tweaks to avoid some warnings --- src/models.c | 18 +++++++++--------- src/rlgl.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/models.c b/src/models.c index c0f043877..ad084f056 100644 --- a/src/models.c +++ b/src/models.c @@ -1411,7 +1411,7 @@ bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, floa float dy = centerA.y - centerB.y; // Y distance between centers float dz = centerA.z - centerB.z; // Y distance between centers - float distance = sqrt(dx*dx + dy*dy + dz*dz); // Distance between centers + float distance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance between centers if (distance <= (radiusA + radiusB)) collision = true; @@ -1441,14 +1441,14 @@ bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radius float dmin = 0; - if (centerSphere.x < box.min.x) dmin += pow(centerSphere.x - box.min.x, 2); - else if (centerSphere.x > box.max.x) dmin += pow(centerSphere.x - box.max.x, 2); + if (centerSphere.x < box.min.x) dmin += powf(centerSphere.x - box.min.x, 2); + else if (centerSphere.x > box.max.x) dmin += powf(centerSphere.x - box.max.x, 2); - if (centerSphere.y < box.min.y) dmin += pow(centerSphere.y - box.min.y, 2); - else if (centerSphere.y > box.max.y) dmin += pow(centerSphere.y - box.max.y, 2); + if (centerSphere.y < box.min.y) dmin += powf(centerSphere.y - box.min.y, 2); + else if (centerSphere.y > box.max.y) dmin += powf(centerSphere.y - box.max.y, 2); - if (centerSphere.z < box.min.z) dmin += pow(centerSphere.z - box.min.z, 2); - else if (centerSphere.z > box.max.z) dmin += pow(centerSphere.z - box.max.z, 2); + if (centerSphere.z < box.min.z) dmin += powf(centerSphere.z - box.min.z, 2); + else if (centerSphere.z > box.max.z) dmin += powf(centerSphere.z - box.max.z, 2); if (dmin <= (radiusSphere*radiusSphere)) collision = true; @@ -1487,8 +1487,8 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi float collisionDistance = 0; // Check if ray origin is inside the sphere to calculate the correct collision point - if (distance < sphereRadius) collisionDistance = vector + sqrt(d); - else collisionDistance = vector - sqrt(d); + if (distance < sphereRadius) collisionDistance = vector + sqrtf(d); + else collisionDistance = vector - sqrtf(d); VectorScale(&offset, collisionDistance); Vector3 cPoint = VectorAdd(ray.position, offset); diff --git a/src/rlgl.c b/src/rlgl.c index e2804e9cc..d3bba07b0 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -3882,7 +3882,7 @@ static void SetStereoConfig(VrDeviceInfo hmd) // Fovy is normally computed with: 2*atan2(hmd.vScreenSize, 2*hmd.eyeToScreenDistance)*RAD2DEG // ...but with lens distortion it is increased (see Oculus SDK Documentation) //float fovy = 2.0f*atan2(hmd.vScreenSize*0.5f*distortionScale, hmd.eyeToScreenDistance)*RAD2DEG; // Really need distortionScale? - float fovy = 2.0f*atan2(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance)*RAD2DEG; + float fovy = 2.0f*(float)atan2(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance)*RAD2DEG; // Compute camera projection matrices float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1] From f2d61d4d432ff302c57d0869d75e72c6462658f5 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 2 Nov 2016 13:39:48 +0100 Subject: [PATCH 21/32] Improved gamepad support on Raspberry Pi --- src/core.c | 19 ++++++++++++++++--- src/raylib.h | 32 +++++++++++++++----------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/core.c b/src/core.c index 3bade07bf..8e15eb96e 100644 --- a/src/core.c +++ b/src/core.c @@ -96,8 +96,8 @@ #include // UNIX System call for device-specific input/output operations - ioctl() #include // Linux: KDSKBMODE, K_MEDIUMRAM constants definition #include // Linux: Keycodes constants definition (KEY_A, ...) - #include - + #include // Linux: Joystick support library + #include "bcm_host.h" // Raspberry Pi VideoCore IV access functions #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions @@ -175,6 +175,7 @@ static pthread_t mouseThreadId; // Mouse reading thread id // Gamepad input variables static int gamepadStream[MAX_GAMEPADS] = { -1 };// Gamepad device file descriptor static pthread_t gamepadThreadId; // Gamepad reading thread id +static char gamepadName[64]; // Gamepad name holder #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -1188,6 +1189,10 @@ const char *GetGamepadName(int gamepad) #if defined(PLATFORM_DESKTOP) if (gamepadReady[gamepad]) return glfwGetJoystickName(gamepad); else return NULL; +#elif defined(PLATFORM_RPI) + if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGNAME(64), &gamepadName); + + return gamepadName; #else return NULL; #endif @@ -1196,6 +1201,11 @@ const char *GetGamepadName(int gamepad) // Return gamepad axis count int GetGamepadAxisCount(int gamepad) { +#if defined(PLATFORM_RPI) + int axisCount = 0; + if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGAXES, &axisCount); + gamepadAxisCount = axisCount; +#endif return gamepadAxisCount; } @@ -1939,9 +1949,11 @@ static void PollInputEvents(void) // Reset last key pressed registered lastKeyPressed = -1; - // Reset last gamepad button pressed registered +#if !defined(PLATFORM_RPI) + // Reset last gamepad button/axis registered state lastGamepadButtonPressed = -1; gamepadAxisCount = 0; +#endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -2850,6 +2862,7 @@ static void *GamepadThread(void *arg) currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value; if ((int)gamepadEvent.value == 1) lastGamepadButtonPressed = gamepadEvent.number; + else lastGamepadButtonPressed = -1; } } else if (gamepadEvent.type == JS_EVENT_AXIS) diff --git a/src/raylib.h b/src/raylib.h index 58037770f..08acafdd1 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -216,8 +216,8 @@ #define GAMEPAD_PS3_AXIS_LEFT_Y 1 #define GAMEPAD_PS3_AXIS_RIGHT_X 2 #define GAMEPAD_PS3_AXIS_RIGHT_Y 5 -#define GAMEPAD_PS3_AXIS_L2 3 // 1.0(not pressed) --> -1.0(completely pressed) -#define GAMEPAD_PS3_AXIS_R2 4 // 1.0(not pressed) --> -1.0(completely pressed) +#define GAMEPAD_PS3_AXIS_L2 3 // [1..-1] (pressure-level) +#define GAMEPAD_PS3_AXIS_R2 4 // [1..-1] (pressure-level) // Xbox360 USB Controller Buttons #define GAMEPAD_XBOX_BUTTON_A 0 @@ -232,27 +232,25 @@ #define GAMEPAD_XBOX_BUTTON_RIGHT 11 #define GAMEPAD_XBOX_BUTTON_DOWN 12 #define GAMEPAD_XBOX_BUTTON_LEFT 13 -#define GAMEPAD_XBOX_BUTTON_HOME 9 +#define GAMEPAD_XBOX_BUTTON_HOME 8 // Xbox360 USB Controller Axis -#define GAMEPAD_XBOX_AXIS_LEFT_X 0 -#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 -#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 -#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 -#define GAMEPAD_XBOX_AXIS_LT 4 // -1.0(not pressed) --> 1.0(completely pressed) -#define GAMEPAD_XBOX_AXIS_RT 5 // -1.0(not pressed) --> 1.0(completely pressed) +#define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) +#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down) +#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right) +#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down) +#define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level) +#define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) -/* // NOTE: For Raspberry Pi, axis must be reconfigured #if defined(PLATFORM_RPI) - #define GAMEPAD_XBOX_AXIS_LEFT_X 7 - #define GAMEPAD_XBOX_AXIS_LEFT_Y 6 - #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 - #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 - #define GAMEPAD_XBOX_AXIS_LT 2 - #define GAMEPAD_XBOX_AXIS_RT 5 + #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [-1..1] (up->down) + #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 // [-1..1] (up->down) + #define GAMEPAD_XBOX_AXIS_LT 2 // [-1..1] (pressure-level) + #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) #endif -*/ // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. From 3be81b01d7463a63d59dd575b7f5d7c267e3c086 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 2 Nov 2016 13:39:58 +0100 Subject: [PATCH 22/32] Brand new gamepad example --- examples/core_input_gamepad.c | 165 +++++++++++++++++++++++++++++----- examples/resources/ps3.png | Bin 0 -> 19345 bytes examples/resources/xbox.png | Bin 0 -> 16177 bytes 3 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 examples/resources/ps3.png create mode 100644 examples/resources/xbox.png diff --git a/examples/core_input_gamepad.c b/examples/core_input_gamepad.c index 6c3568297..77d11f386 100644 --- a/examples/core_input_gamepad.c +++ b/examples/core_input_gamepad.c @@ -3,17 +3,29 @@ * raylib [core] example - Gamepad input * * NOTE: This example requires a Gamepad connected to the system -* raylib is configured to work with Xbox 360 gamepad, check raylib.h for buttons configuration +* raylib is configured to work with the following gamepads: +* Xbox 360 Controller (Xbox 360, Xbox One) +* PLAYSTATION(R)3 Controller +* Check raylib.h for buttons configuration * -* This example has been created using raylib 1.0 (www.raylib.com) +* This example has been created using raylib 1.6 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" +// NOTE: Gamepad name ID depends on drivers and OS +#if defined(PLATFORM_RPI) + #define XBOX360_NAME_ID "Microsoft X-Box 360 pad" + #define PS3_NAME_ID "PLAYSTATION(R)3 Controller" +#else + #define XBOX360_NAME_ID "Xbox 360 Controller" + #define PS3_NAME_ID "PLAYSTATION(R)3 Controller" +#endif + int main() { // Initialization @@ -21,12 +33,14 @@ int main() int screenWidth = 800; int screenHeight = 450; + SetConfigFlags(FLAG_MSAA_4X_HINT); // Set MSAA 4X hint before windows creation + InitWindow(screenWidth, screenHeight, "raylib [core] example - gamepad input"); + + Texture2D texPs3Pad = LoadTexture("resources/ps3.png"); + Texture2D texXboxPad = LoadTexture("resources/xbox.png"); - Vector2 ballPosition = { (float)screenWidth/2, (float)screenHeight/2 }; - Vector2 gamepadMovement = { 0.0f, 0.0f }; - - SetTargetFPS(60); // Set target frames-per-second + SetTargetFPS(60); //-------------------------------------------------------------------------------------- // Main game loop @@ -34,20 +48,7 @@ int main() { // Update //---------------------------------------------------------------------------------- - if (IsGamepadAvailable(GAMEPAD_PLAYER1)) - { - gamepadMovement.x = GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_X); - gamepadMovement.y = GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_Y); - - ballPosition.x += gamepadMovement.x; - ballPosition.y -= gamepadMovement.y; - - if (IsGamepadButtonPressed(GAMEPAD_PLAYER1, GAMEPAD_BUTTON_A)) - { - ballPosition.x = (float)screenWidth/2; - ballPosition.y = (float)screenHeight/2; - } - } + // ... //---------------------------------------------------------------------------------- // Draw @@ -55,10 +56,125 @@ int main() BeginDrawing(); ClearBackground(RAYWHITE); + + if (IsGamepadAvailable(GAMEPAD_PLAYER1)) + { + DrawText(FormatText("GP1: %s", GetGamepadName(GAMEPAD_PLAYER1)), 10, 10, 10, BLACK); - DrawText("move the ball with gamepad", 10, 10, 20, DARKGRAY); + if (IsGamepadName(GAMEPAD_PLAYER1, XBOX360_NAME_ID)) + { + DrawTexture(texXboxPad, 0, 0, DARKGRAY); + + // Draw buttons: xbox home + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_HOME)) DrawCircle(396, 222, 13, RED); - DrawCircleV(ballPosition, 50, MAROON); + // Draw buttons: basic + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_START)) DrawCircle(436, 150, 9, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_SELECT)) DrawCircle(352, 150, 9, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_X)) DrawCircle(501, 151, 15, BLUE); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_A)) DrawCircle(536, 187, 15, LIME); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_B)) DrawCircle(572, 151, 15, MAROON); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_Y)) DrawCircle(536, 115, 15, GOLD); + + // Draw buttons: d-pad + DrawRectangle(317, 202, 19, 71, BLACK); + DrawRectangle(293, 228, 69, 19, BLACK); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_UP)) DrawRectangle(317, 202, 19, 26, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_DOWN)) DrawRectangle(317, 202 + 45, 19, 26, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_LEFT)) DrawRectangle(292, 228, 25, 19, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_RIGHT)) DrawRectangle(292 + 44, 228, 26, 19, RED); + + // Draw buttons: left-right back + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_LB)) DrawCircle(259, 61, 20, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_RB)) DrawCircle(536, 61, 20, RED); + + // Draw axis: left joystick + DrawCircle(259, 152, 39, BLACK); + DrawCircle(259, 152, 34, LIGHTGRAY); + DrawCircle(259 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_X)*20), + 152 - (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_Y)*20), 25, BLACK); + + // Draw axis: right joystick + DrawCircle(461, 237, 38, BLACK); + DrawCircle(461, 237, 33, LIGHTGRAY); + DrawCircle(461 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_RIGHT_X)*20), + 237 - (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_RIGHT_Y)*20), 25, BLACK); + + // Draw axis: left-right triggers + DrawRectangle(170, 30, 15, 70, GRAY); + DrawRectangle(604, 30, 15, 70, GRAY); + DrawRectangle(170, 30, 15, (((1.0f + GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LT))/2.0f)*70), RED); + DrawRectangle(604, 30, 15, (((1.0f + GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_RT))/2.0f)*70), RED); + + //DrawText(FormatText("Xbox axis LT: %02.02f", GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LT)), 10, 40, 10, BLACK); + //DrawText(FormatText("Xbox axis RT: %02.02f", GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_RT)), 10, 60, 10, BLACK); + } + else if (IsGamepadName(GAMEPAD_PLAYER1, PS3_NAME_ID)) + { + DrawTexture(texPs3Pad, 0, 0, DARKGRAY); + + // Draw buttons: ps + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_PS)) DrawCircle(396, 222, 13, RED); + + // Draw buttons: basic + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_SELECT)) DrawRectangle(328, 170, 32, 13, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_START)) DrawTriangle((Vector2){ 436, 168 }, (Vector2){ 436, 185 }, (Vector2){ 464, 177 }, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_TRIANGLE)) DrawCircle(557, 144, 13, LIME); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_CIRCLE)) DrawCircle(586, 173, 13, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_CROSS)) DrawCircle(557, 203, 13, VIOLET); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_SQUARE)) DrawCircle(527, 173, 13, PINK); + + // Draw buttons: d-pad + DrawRectangle(225, 132, 24, 84, BLACK); + DrawRectangle(195, 161, 84, 25, BLACK); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_UP)) DrawRectangle(225, 132, 24, 29, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_DOWN)) DrawRectangle(225, 132 + 54, 24, 30, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_LEFT)) DrawRectangle(195, 161, 30, 25, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_RIGHT)) DrawRectangle(195 + 54, 161, 30, 25, RED); + + // Draw buttons: left-right back buttons + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_L1)) DrawCircle(239, 82, 20, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_PS3_BUTTON_R1)) DrawCircle(557, 82, 20, RED); + + // Draw axis: left joystick + DrawCircle(319, 255, 35, BLACK); + DrawCircle(319, 255, 31, LIGHTGRAY); + DrawCircle(319 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_PS3_AXIS_LEFT_X)*20), + 255 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_PS3_AXIS_LEFT_Y)*20), 25, BLACK); + + // Draw axis: right joystick + DrawCircle(475, 255, 35, BLACK); + DrawCircle(475, 255, 31, LIGHTGRAY); + DrawCircle(475 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_PS3_AXIS_RIGHT_X)*20), + 255 + (GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_PS3_AXIS_RIGHT_Y)*20), 25, BLACK); + + // Draw axis: left-right triggers + DrawRectangle(169, 48, 15, 70, GRAY); + DrawRectangle(611, 48, 15, 70, GRAY); + DrawRectangle(169, 48, 15, (((1.0f - GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_PS3_AXIS_L2))/2.0f)*70), RED); + DrawRectangle(611, 48, 15, (((1.0f - GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_PS3_AXIS_R2))/2.0f)*70), RED); + } + else + { + // TODO: Draw generic gamepad + } + + DrawText(FormatText("DETECTED AXIS [%i]:", GetGamepadAxisCount(GAMEPAD_PLAYER1)), 10, 50, 10, MAROON); + + for (int i = 0; i < GetGamepadAxisCount(GAMEPAD_PLAYER1); i++) + { + DrawText(FormatText("AXIS %i: %.02f", i, GetGamepadAxisMovement(GAMEPAD_PLAYER1, i)), 20, 70 + 20*i, 10, DARKGRAY); + } + + if (GetGamepadButtonPressed() != -1) DrawText(FormatText("DETECTED BUTTON: %i", GetGamepadButtonPressed()), 10, 430, 10, RED); + else DrawText("DETECTED BUTTON: NONE", 10, 430, 10, GRAY); + } + else + { + DrawText("GP1: NOT DETECTED", 10, 10, 10, GRAY); + + DrawTexture(texXboxPad, 0, 0, LIGHTGRAY); + } EndDrawing(); //---------------------------------------------------------------------------------- @@ -66,6 +182,9 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- + UnloadTexture(texPs3Pad); + UnloadTexture(texXboxPad); + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/resources/ps3.png b/examples/resources/ps3.png new file mode 100644 index 0000000000000000000000000000000000000000..98befacc43a657aa442d7998c2142bb64325876d GIT binary patch literal 19345 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 BXzTz0 literal 0 HcmV?d00001 diff --git a/examples/resources/xbox.png b/examples/resources/xbox.png new file mode 100644 index 0000000000000000000000000000000000000000..029c91090bb75765d26402274191cbeb10b87b2b GIT binary patch literal 16177 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 literal 0 HcmV?d00001 From ed4fdfdaf8b2b37a4c62d6289bd340feb8ccf7fa Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 3 Nov 2016 16:18:07 +0100 Subject: [PATCH 23/32] Example tweak --- examples/core_input_gamepad.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/core_input_gamepad.c b/examples/core_input_gamepad.c index 77d11f386..f98885e3c 100644 --- a/examples/core_input_gamepad.c +++ b/examples/core_input_gamepad.c @@ -66,7 +66,7 @@ int main() DrawTexture(texXboxPad, 0, 0, DARKGRAY); // Draw buttons: xbox home - if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_HOME)) DrawCircle(396, 222, 13, RED); + if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_HOME)) DrawCircle(394, 89, 19, RED); // Draw buttons: basic if (IsGamepadButtonDown(GAMEPAD_PLAYER1, GAMEPAD_XBOX_BUTTON_START)) DrawCircle(436, 150, 9, RED); @@ -156,6 +156,8 @@ int main() } else { + DrawText("- GENERIC GAMEPAD -", 280, 180, 20, GRAY); + // TODO: Draw generic gamepad } From ca96122a7b8291f0761fd34f1997e1a051b907f2 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 3 Nov 2016 18:57:16 +0100 Subject: [PATCH 24/32] Raspberry Pi custom gamepad axis --- src/raylib.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 08acafdd1..00d27466f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -235,13 +235,6 @@ #define GAMEPAD_XBOX_BUTTON_HOME 8 // Xbox360 USB Controller Axis -#define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) -#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down) -#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right) -#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down) -#define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level) -#define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) - // NOTE: For Raspberry Pi, axis must be reconfigured #if defined(PLATFORM_RPI) #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) @@ -250,6 +243,13 @@ #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 // [-1..1] (up->down) #define GAMEPAD_XBOX_AXIS_LT 2 // [-1..1] (pressure-level) #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) +#else + #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down) + #define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down) + #define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level) + #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) #endif // NOTE: MSC C++ compiler does not support compound literals (C99 feature) From aa945055fae4f76d428704ecbc9840b57aada35a Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 3 Nov 2016 18:57:46 +0100 Subject: [PATCH 25/32] Corrected issue on chars drawing Support by default unordered charsets --- src/text.c | 64 +++++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/src/text.c b/src/text.c index 23041603d..728e6fbe7 100644 --- a/src/text.c +++ b/src/text.c @@ -344,13 +344,13 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color) void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float fontSize, int spacing, Color tint) { int length = strlen(text); - int textOffsetX = 0; - int textOffsetY = 0; // Line break! + int textOffsetX = 0; // Offset between characters + int textOffsetY = 0; // Required for line break! float scaleFactor; - unsigned char letter; - - Rectangle rec; - + + unsigned char letter; // Current character + int index; // Index position in sprite font + scaleFactor = fontSize/spriteFont.size; // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly @@ -358,41 +358,37 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float for (int i = 0; i < length; i++) { - if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! + if ((unsigned char)text[i] == '\n') { - // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) - letter = (unsigned char)text[i + 1]; - rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)letter)]; - i++; - } - else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! - { - // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) - letter = (unsigned char)text[i + 1]; - rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)letter + 64)]; - i++; + // NOTE: Fixed line spacing of 1.5 lines + textOffsetY += ((spriteFont.size + spriteFont.size/2)*scaleFactor); + textOffsetX = 0; } else { - if ((unsigned char)text[i] == '\n') + if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! { - // NOTE: Fixed line spacing of 1.5 lines - textOffsetY += ((spriteFont.size + spriteFont.size/2)*scaleFactor); - textOffsetX = 0; - rec.x = -1; + // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) + letter = (unsigned char)text[i + 1]; + index = GetCharIndex(spriteFont, (int)letter); + i++; } - else rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)text[i])]; - } + else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! + { + // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) + letter = (unsigned char)text[i + 1]; + index = GetCharIndex(spriteFont, (int)letter + 64); + i++; + } + else index = GetCharIndex(spriteFont, (int)text[i]); - if (rec.x >= 0) - { - int index = GetCharIndex(spriteFont, (int)text[i]); - - DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor, - position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor, - rec.width*scaleFactor, rec.height*scaleFactor} , (Vector2){ 0, 0 }, 0.0f, tint); + DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index], + (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor, + position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor, + spriteFont.charRecs[index].width*scaleFactor, + spriteFont.charRecs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); - if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (rec.width*scaleFactor + spacing); + if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (spriteFont.charRecs[index].width*scaleFactor + spacing); else textOffsetX += (spriteFont.charAdvanceX[index]*scaleFactor + spacing); } } @@ -535,7 +531,7 @@ void DrawFPS(int posX, int posY) static int GetCharIndex(SpriteFont font, int letter) { -//#define UNORDERED_CHARSET +#define UNORDERED_CHARSET #if defined(UNORDERED_CHARSET) int index = 0; From 66d22acfb38ca8f8698ae7caffaa3f31ece3024f Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 6 Nov 2016 10:06:18 +0100 Subject: [PATCH 26/32] Improve text example --- examples/text_writing_anim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/text_writing_anim.c b/examples/text_writing_anim.c index 5f19b4682..5563b561c 100644 --- a/examples/text_writing_anim.c +++ b/examples/text_writing_anim.c @@ -32,7 +32,8 @@ int main() { // Update //---------------------------------------------------------------------------------- - framesCounter++; + if (IsKeyDown(KEY_SPACE)) framesCounter += 8; + else framesCounter++; if (IsKeyPressed(KEY_ENTER)) framesCounter = 0; //---------------------------------------------------------------------------------- @@ -45,7 +46,8 @@ int main() DrawText(SubText(message, 0, framesCounter/10), 210, 160, 20, MAROON); - DrawText("PRESS [ENTER] to RESTART!", 240, 280, 20, LIGHTGRAY); + DrawText("PRESS [ENTER] to RESTART!", 240, 260, 20, LIGHTGRAY); + DrawText("PRESS [SPACE] to SPEED UP!", 239, 300, 20, LIGHTGRAY); EndDrawing(); //---------------------------------------------------------------------------------- From 773b0b6bc031b17dae61d78bca23d820f3c81a19 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 6 Nov 2016 14:09:30 +0100 Subject: [PATCH 27/32] Update ROADMAP.md --- ROADMAP.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 129551034..56ff761ec 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,16 +4,16 @@ roadmap Current version of raylib is quite complete and functional but there is still a lot of things to add and improve. Here it is a wish list of features I would like to add and functions to improve. -Note that around the raylib source code there are multiple TODO points with pending revisions/bugs. Check [GitHub Issues](https://github.com/raysan5/raylib/issues) for further details! +Note raylib source code has multiple TODO points with pending things to review and improve. Check [GitHub Issues](https://github.com/raysan5/raylib/issues) for further details! raylib 1.x - [IN PROGRESS] LUA scripting support (wrapper to lua lib) + [DONE] LUA scripting support (wrapper to lua lib) Basic GPU stats sytem (memory, draws, time...) + Improved custom file-format (.rres) and packaging tool Procedural image generation functions (spot, gradient, noise...) Procedural mesh generation functions (cube, cone, sphere...) Touch-based camera controls for Android - Skybox and Fog support raylib 1.5 From 42452378925e3b1d407a33084cd8cf0495632ee8 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 13 Nov 2016 23:47:28 +0100 Subject: [PATCH 28/32] Corrected SIGSEV bug --- src/models.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models.c b/src/models.c index ad084f056..b7e36b8a0 100644 --- a/src/models.c +++ b/src/models.c @@ -1811,7 +1811,7 @@ static Material LoadMTL(const char *fileName) char buffer[MAX_BUFFER_SIZE]; Vector3 color = { 1.0f, 1.0f, 1.0f }; - char *mapFileName = NULL; + char mapFileName[128]; FILE *mtlFile; From 38df2cad253251c9fc531c2e9a3a28308aaeb718 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 13 Nov 2016 23:53:28 +0100 Subject: [PATCH 29/32] Improved text measurement Still not working correctly, font offsets are not considered correctly... --- src/text.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/text.c b/src/text.c index 728e6fbe7..72d273d41 100644 --- a/src/text.c +++ b/src/text.c @@ -444,14 +444,14 @@ int MeasureText(const char *text, int fontSize) if (fontSize < defaultFontSize) fontSize = defaultFontSize; int spacing = fontSize/defaultFontSize; - vec = MeasureTextEx(GetDefaultFont(), text, fontSize, spacing); + vec = MeasureTextEx(GetDefaultFont(), text, (float)fontSize, spacing); } return (int)vec.x; } // Measure string size for SpriteFont -Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing) +Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing) { int len = strlen(text); int tempLen = 0; // Used to count longer text line num chars @@ -461,7 +461,7 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int int tempTextWidth = 0; // Used to count longer text line width int textHeight = spriteFont.size; - float scaleFactor; + float scaleFactor = fontSize/spriteFont.size; for (int i = 0; i < len; i++) { @@ -487,9 +487,6 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int if (tempTextWidth < textWidth) tempTextWidth = textWidth; - if (fontSize <= spriteFont.size) scaleFactor = 1.0f; - else scaleFactor = (float)fontSize/spriteFont.size; - Vector2 vec; vec.x = (float)tempTextWidth*scaleFactor + (tempLen - 1)*spacing; // Adds chars spacing to measure vec.y = (float)textHeight*scaleFactor; From 9fb6eda5f103e383f3a15d7c2a4d014752dce087 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 13 Nov 2016 23:54:36 +0100 Subject: [PATCH 30/32] Improved text measurement --- src/raylib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raylib.h b/src/raylib.h index 00d27466f..f62433041 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -826,7 +826,7 @@ RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color co RLAPI void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters float fontSize, int spacing, Color tint); RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font -RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing); // Measure string size for SpriteFont +RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing); // Measure string size for SpriteFont RLAPI void DrawFPS(int posX, int posY); // Shows current FPS on top-left corner RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' From 2b50440a77e61b81c832560cee22ba74ba1e47ba Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 13 Nov 2016 23:55:37 +0100 Subject: [PATCH 31/32] Review ROADMAP --- ROADMAP.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 56ff761ec..4c153d78e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -8,12 +8,17 @@ Note raylib source code has multiple TODO points with pending things to review a raylib 1.x - [DONE] LUA scripting support (wrapper to lua lib) Basic GPU stats sytem (memory, draws, time...) Improved custom file-format (.rres) and packaging tool Procedural image generation functions (spot, gradient, noise...) Procedural mesh generation functions (cube, cone, sphere...) Touch-based camera controls for Android + Gamepad support on HTML5 + +raylib 1.6 + + [DONE] LUA scripting support (raylib lua wrapper) + [DONE] Redesigned audio module raylib 1.5 From a3d71dd58d993d15d695b0cd58b434ef2604185b Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 14 Nov 2016 00:05:49 +0100 Subject: [PATCH 32/32] Updated for raylib 1.6 --- CHANGELOG | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- README.md | 26 ++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0e437ded0..87052478c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,59 @@ changelog --------- -Current Release: raylib 1.5.0 (18 July 2016) +Current Release: raylib 1.6.0 (20 November 2016) -NOTE: Only versions marked as 'Release' are available in installer, updates are only available as source. -NOTE: Current Release includes all previous updates. +----------------------------------------------- +Release: raylib 1.6.0 (20 November 2016) +----------------------------------------------- +NOTE: + This new raylib version commemorates raylib 3rd anniversary and represents another complete review of the library. + It includes some interesting new features and is a stepping stone towards raylib future. + +HUGE changes: +[rlua] LUA BINDING: Complete raylib LUA binding, all raylib functions ported to LUA plus the +60 code examples. +[audio] COMPLETE REDESIGN: Improved music support and also raw audio data processing and playing. FLAC support added. +[physac] COMPLETE REWRITE: Improved performance, functionality and simplified usage, moved to own repository and added multiple examples! + +other changes: + +[core] Corrected issue on OSX with HighDPI display +[core] Added flag to allow resizable window +[core] Allow no default font loading +[core] Corrected old issue with mouse buttons on web +[core] Improved gamepad support, unified across platforms +[core] Reviewed Android key inputs system, unified with desktop +[rlgl] Redesigned lighting shader system +[rlgl] Reviewed UpdateVrTracking() and rlglLoadRenderTexture() +[rlgl] Updated standard shader for better performance +[shapes] Corrected issue on DrawPolyEx() +[textures] Simplified supported image formats support +[textures] Improved text drawing within an image: ImageDrawText() +[textures] Support image alpha mixing: ImageAlphaMask() +[textures] Support textures filtering: SetTextureFilter() +[textures] Support textures wrap modes: SetTextureWrap() +[text] Improved TTF spritefont generation: LoadSpriteFontTTF() +[text] Improved AngelCode fonts support +[text] Reviewed spacing formatting +[text] Added TraceLog info on image spritefont loading +[text] Improved text measurement: MeasureTextEx() +[models] Improved OBJ loading flexibility +[models] Removed function: ResolveCollisionCubicmap() +[camera] Redesigned camera system and ported to header-only +[gestures] Redesigned gestures module to header-only +[audio] Simplified Music loading and playing system +[audio] Added trace on audio device closing +[audio] Reviewed Wave struct for reter flexivility +[audio] Support sound data update: UpdateSound() +[audio] Added support for FLAC audio loading/streaming +[raygui] Removed raygui from raylib repo (moved to own repo) +[build] Added OpenAL static library +[build] Added Visual Studio 2015 projects +[build] Support shared/dynamic raylib compilation +[*] Updated LibOVR to SDK version 1.8 +[*] Updated games to latest raylib version +[*] Improved Android support +[*] Improved examples and added new ones ----------------------------------------------- Release: raylib 1.5.0 (18 July 2016) diff --git a/README.md b/README.md index 64cfcc530..2f4ad984f 100644 --- a/README.md +++ b/README.md @@ -153,11 +153,33 @@ Up to 8 new code examples have been added to show the new raylib features and al Lots of code changes (+400 commits) and lots of hours of hard work have concluded in this amazing new raylib 1.5. +notes on raylib 1.6 +------------------- + +On November 2016, only 4 months after raylib 1.5, arrives raylib 1.6. This new version represents another big review of the library and includes some interesting additions. This version conmmemorates raylib 3rd anniversary (raylib 1.0 was published on November 2013) and it is a stepping stone for raylib future. raylib roadmap has been reviewed and redefined to focus on its primary objective: create a simple and easy-to-use library to learn videogames programming. Some of the new features: + +Complete raylib LUA binding. All raylib functions plus the +60 code examples have been ported to LUA, now LUA users can enjoy coding videogames in LUA while using all the internal power of raylib. This addition also open the doors to LUA scripting support for a future raylib-based engine, being able to move game logic (Init, Update, Draw, De-Init) to LUA scripts while keep using raylib functionality. + +Completely redesigned audio module. Based on the new direction taken in raylib 1.5, it has been further improved and more functionality added to allow raw audio processing and playing. FLAC file format support has also been added. In the same line, OpenAL Soft backend is now provided as a static library in Windows to allow static linking and get ride of OpenAL32.dll. Now raylib Windows games are completey self-contained, no external libraries required any more! + +Camera and gestures modules have been reviewed, highly simplified and ported to single-file header-only libraries for easier portability and usage flexibility. Consequently, camera system usage has been simplified in all examples. + +Improved Gamepad support on Windows and Raspberry Pi with the addition of new functions for custom gamepad configurations but supporting by default PS3 and Xbox-based gamepads. + +Improved textures and text functionality, adding new functions for texture filtering control and better TTF/AngelCode fonts loading and generation support. + +Physac module has been moved to its own repository and it has been improved A LOT, actually, library has been completely rewritten by @victorfisac, multiple samples have been added and countless new features to match current standard 2D physic libraries. + +Build system improvement. Added support for raylib dynamic library generation (raylib.dll) for users that prefer dynamic library linking. Also thinking on advance users, it has been added pre-configured Visual Studio C++ 2015 solution with raylib project and C/C++ examples for users that prefer that professional IDE and compiler. + +New examples, new functions, complete code-base review, multiple bugs corrected... this is raylib 1.6. Enjoy making games. + + features -------- * Written in plain C code (C99) - * Uses C# PascalCase/camelCase notation + * Uses PascalCase/camelCase notation * Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES2) * Unique OpenGL abstraction layer (usable as standalone module): [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.c) * Powerful fonts module with multiple SpriteFonts formats support (XNA bitmap fonts, AngelCode fonts, TTF) @@ -166,7 +188,7 @@ features * Materials (diffuse, normal, specular) and Lighting (point, directional, spot) support * Shaders support, including Model shaders and Postprocessing shaders * Powerful math module for Vector and Matrix operations: [raymath](https://github.com/raysan5/raylib/blob/master/src/raymath.c) - * Audio loading and playing with streaming support and mixing channels (WAV, OGG, XM, MOD) + * Audio loading and playing with streaming support and mixing channels (WAV, OGG, FLAC, XM, MOD) * VR stereo rendering support with configurable HMD device parameters * Multiple platforms support: Windows, Linux, Mac, **Android**, **Raspberry Pi**, **HTML5** and **Oculus Rift CV1** * Custom color palette for fancy visuals on raywhite background