2013-11-19 02:38:44 +04:00
|
|
|
/*********************************************************************************************
|
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
* raylib.core
|
2013-11-19 02:38:44 +04:00
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
* Basic functions to manage Windows, OpenGL context and Input
|
|
|
|
*
|
|
|
|
* Uses external lib:
|
|
|
|
* GLFW3 - Window, context and Input management (static lib version)
|
2013-11-19 02:38:44 +04:00
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
|
|
|
|
*
|
|
|
|
* 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.
|
2013-11-19 02:38:44 +04:00
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
* Permission is granted to anyone to use this software for any purpose, including commercial
|
|
|
|
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
2013-11-19 02:38:44 +04:00
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
|
|
|
* wrote the original software. If you use this software in a product, an acknowledgment
|
|
|
|
* in the product documentation would be appreciated but is not required.
|
2013-11-19 02:38:44 +04:00
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
|
|
|
* as being the original software.
|
2013-11-19 02:38:44 +04:00
|
|
|
*
|
2013-11-23 16:30:54 +04:00
|
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
2013-11-19 02:38:44 +04:00
|
|
|
*
|
|
|
|
**********************************************************************************************/
|
|
|
|
|
|
|
|
#include "raylib.h"
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
#include <GLFW/glfw3.h> // GLFW3 lib: Windows, OpenGL context and Input management
|
|
|
|
//#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h)
|
|
|
|
#include <stdio.h> // Standard input / output lib
|
2013-12-19 15:08:06 +04:00
|
|
|
#include <stdlib.h> // Declares malloc() and free() for memory management, rand()
|
|
|
|
#include <time.h> // Useful to initialize random seed
|
2014-03-16 23:59:02 +04:00
|
|
|
#include <math.h> // Math related functions, tan() used to set perspective
|
2014-03-25 15:40:35 +04:00
|
|
|
//#include "vector3.h" // Basic Vector3 functions, not required any more, replaced by raymath
|
2014-01-23 15:36:18 +04:00
|
|
|
#include "utils.h" // WritePNG() function
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
#include "raymath.h" // Required for data type Matrix and Matrix functions
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
//#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version!
|
2013-11-19 02:38:44 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Defines and Macros
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Nop...
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Types and Structures Definition
|
|
|
|
//----------------------------------------------------------------------------------
|
2014-03-25 15:40:35 +04:00
|
|
|
// ...
|
2013-11-19 02:38:44 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Global Variables Definition
|
|
|
|
//----------------------------------------------------------------------------------
|
2013-11-23 16:30:54 +04:00
|
|
|
static GLFWwindow* window; // Main window
|
|
|
|
static bool fullscreen; // Fullscreen mode track
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
static double currentTime, previousTime; // Used to track timmings
|
|
|
|
static double updateTime, drawTime; // Time measures for update and draw
|
|
|
|
static double frameTime; // Time measure for one frame
|
|
|
|
static double targetTime = 0; // Desired time for one frame, if 0 not applied
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
static int windowWidth, windowHeight; // Required to switch between windowed/fullscren mode (F11)
|
2013-12-19 15:08:06 +04:00
|
|
|
static const char *windowTitle; // Required to switch between windowed/fullscren mode (F11)
|
2014-03-25 15:40:35 +04:00
|
|
|
static int exitKey = GLFW_KEY_ESCAPE; // Default exit key (ESC)
|
2013-12-19 15:08:06 +04:00
|
|
|
|
|
|
|
static bool customCursor = false; // Tracks if custom cursor has been set
|
|
|
|
static bool cursorOnScreen = false; // Tracks if cursor is inside client area
|
|
|
|
static Texture2D cursor; // Cursor texture
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2013-11-28 22:59:56 +04:00
|
|
|
static char previousKeyState[512] = { 0 }; // Required to check if key pressed/released once
|
|
|
|
static char currentKeyState[512] = { 0 }; // Required to check if key pressed/released once
|
|
|
|
|
|
|
|
static char previousMouseState[3] = { 0 }; // Required to check if mouse btn pressed/released once
|
|
|
|
static char currentMouseState[3] = { 0 }; // Required to check if mouse btn pressed/released once
|
|
|
|
|
|
|
|
static char previousGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once
|
|
|
|
static char currentGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
static int previousMouseWheelY = 0; // Required to track mouse wheel variation
|
|
|
|
static int currentMouseWheelY = 0; // Required to track mouse wheel variation
|
|
|
|
|
|
|
|
static Color background = { 0, 0, 0, 0 }; // Screen background color
|
2014-01-29 00:21:29 +04:00
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Other Modules Functions Declaration (required by core)
|
|
|
|
//----------------------------------------------------------------------------------
|
2014-04-19 18:36:49 +04:00
|
|
|
extern void LoadDefaultFont(); // [Module: text] Loads default font on InitWindow()
|
|
|
|
extern void UnloadDefaultFont(); // [Module: text] Unloads default font from GPU memory
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2014-04-19 18:36:49 +04:00
|
|
|
extern void UpdateMusicStream(); // [Module: audio] Updates buffers for music streaming
|
2014-04-09 22:25:26 +04:00
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Module specific Functions Declaration
|
|
|
|
//----------------------------------------------------------------------------------
|
2013-11-23 16:30:54 +04:00
|
|
|
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
|
|
|
|
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
|
2014-01-29 00:21:29 +04:00
|
|
|
static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
|
2013-12-19 15:08:06 +04:00
|
|
|
static void CursorEnterCallback(GLFWwindow* window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
|
2013-11-23 16:30:54 +04:00
|
|
|
static void WindowSizeCallback(GLFWwindow* window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
|
2014-04-19 18:36:49 +04:00
|
|
|
static void TakeScreenshot(); // Takes a screenshot and saves it in the same folder as executable
|
2013-11-19 02:38:44 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Module Functions Definition - Window and OpenGL Context Functions
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Initialize Window and Graphics Context (OpenGL)
|
2013-12-19 15:08:06 +04:00
|
|
|
void InitWindow(int width, int height, const char *title)
|
|
|
|
{
|
|
|
|
InitWindowEx(width, height, title, true, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize Window and Graphics Context (OpenGL) with extended parameters
|
|
|
|
void InitWindowEx(int width, int height, const char* title, bool resizable, const char *cursorImage)
|
2013-11-19 02:38:44 +04:00
|
|
|
{
|
|
|
|
glfwSetErrorCallback(ErrorCallback);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2014-04-09 22:25:26 +04:00
|
|
|
if (!glfwInit()) TraceLog(ERROR, "Failed to initialize GLFW");
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2013-12-19 15:08:06 +04:00
|
|
|
//glfwDefaultWindowHints() // Set default windows hints
|
2014-03-25 15:40:35 +04:00
|
|
|
|
2013-12-19 15:08:06 +04:00
|
|
|
if (!resizable) glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
|
2014-03-25 15:40:35 +04:00
|
|
|
|
|
|
|
#ifdef USE_OPENGL_33
|
|
|
|
//glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
|
|
|
|
#endif
|
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
window = glfwCreateWindow(width, height, title, NULL, NULL);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
windowWidth = width;
|
|
|
|
windowHeight = height;
|
|
|
|
windowTitle = title;
|
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
if (!window)
|
|
|
|
{
|
|
|
|
glfwTerminate();
|
2014-04-09 22:25:26 +04:00
|
|
|
TraceLog(ERROR, "Failed to initialize Window");
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
glfwSetWindowSizeCallback(window, WindowSizeCallback);
|
2013-12-19 15:08:06 +04:00
|
|
|
glfwSetCursorEnterCallback(window, CursorEnterCallback);
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
glfwMakeContextCurrent(window);
|
|
|
|
glfwSetKeyCallback(window, KeyCallback);
|
2014-01-29 00:21:29 +04:00
|
|
|
glfwSetScrollCallback(window, ScrollCallback);
|
2013-11-23 16:30:54 +04:00
|
|
|
glfwSwapInterval(0); // Disables GPU v-sync (if set), so frames are not limited to screen refresh rate (60Hz -> 60 FPS)
|
|
|
|
// If not set, swap interval uses GPU v-sync configuration
|
|
|
|
// Framerate can be setup using SetTargetFPS()
|
2014-03-25 15:40:35 +04:00
|
|
|
|
|
|
|
//------------------------------------------------------
|
2014-04-09 22:25:26 +04:00
|
|
|
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
|
2014-03-25 15:40:35 +04:00
|
|
|
rlglInit(); // Init rlgl
|
|
|
|
#endif
|
|
|
|
//------------------------------------------------------
|
|
|
|
|
|
|
|
int fbWidth, fbHeight;
|
|
|
|
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
|
|
|
|
|
|
|
|
//------------------------------------------------------
|
|
|
|
rlglInitGraphicsDevice(fbWidth, fbHeight);
|
|
|
|
//------------------------------------------------------
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
previousTime = glfwGetTime();
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
LoadDefaultFont(); // NOTE: External function (defined in module: text)
|
2013-12-19 15:08:06 +04:00
|
|
|
|
2014-03-16 23:59:02 +04:00
|
|
|
if (cursorImage != NULL) SetCustomCursor(cursorImage);
|
2013-12-19 15:08:06 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
srand(time(NULL)); // Initialize random seed
|
|
|
|
|
|
|
|
ClearBackground(RAYWHITE); // Default background color for raylib games :P
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close Window and Terminate Context
|
|
|
|
void CloseWindow()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
UnloadDefaultFont();
|
2014-03-25 15:40:35 +04:00
|
|
|
|
|
|
|
//------------------------------------------------------
|
2014-04-09 22:25:26 +04:00
|
|
|
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
|
2014-03-25 15:40:35 +04:00
|
|
|
rlglClose(); // De-init rlgl
|
|
|
|
#endif
|
|
|
|
//------------------------------------------------------
|
2013-11-19 02:38:44 +04:00
|
|
|
|
|
|
|
glfwDestroyWindow(window);
|
2013-11-23 16:30:54 +04:00
|
|
|
glfwTerminate();
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
2013-12-19 15:08:06 +04:00
|
|
|
// Set a custom cursor icon/image
|
|
|
|
void SetCustomCursor(const char *cursorImage)
|
|
|
|
{
|
|
|
|
if (customCursor) UnloadTexture(cursor);
|
|
|
|
|
|
|
|
cursor = LoadTexture(cursorImage);
|
|
|
|
|
|
|
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
|
|
|
customCursor = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set a custom key to exit program
|
|
|
|
// NOTE: default exitKey is ESCAPE
|
|
|
|
void SetExitKey(int key)
|
|
|
|
{
|
|
|
|
exitKey = key;
|
|
|
|
}
|
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
// Detect if KEY_ESCAPE pressed or Close icon pressed
|
|
|
|
bool WindowShouldClose()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
return (glfwWindowShouldClose(window));
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fullscreen toggle (by default F11)
|
|
|
|
void ToggleFullscreen()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
if (glfwGetKey(window, GLFW_KEY_F11))
|
|
|
|
{
|
|
|
|
fullscreen = !fullscreen; // Toggle fullscreen flag
|
|
|
|
|
2014-03-16 23:59:02 +04:00
|
|
|
UnloadDefaultFont();
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
glfwDestroyWindow(window); // Destroy the current window (we will recreate it!)
|
2014-01-29 00:21:29 +04:00
|
|
|
|
|
|
|
// TODO: WARNING! All loaded resources are lost, we loose Context!
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
// NOTE: Window aspect ratio is always windowWidth / windowHeight
|
2014-04-09 22:25:26 +04:00
|
|
|
if (fullscreen)
|
|
|
|
{
|
|
|
|
// TODO: Get desktop window size and adapt aspect-ratio (?)
|
|
|
|
//const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
|
|
|
//windowWidth = mode->width;
|
|
|
|
//windowHeight = mode->height;
|
|
|
|
|
|
|
|
window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); // Fullscreen mode
|
|
|
|
}
|
2013-11-23 16:30:54 +04:00
|
|
|
else window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, NULL, NULL);
|
2014-04-09 22:25:26 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
if (!window)
|
|
|
|
{
|
|
|
|
glfwTerminate();
|
2014-04-09 22:25:26 +04:00
|
|
|
TraceLog(ERROR, "Failed to initialize Window when switching fullscreen mode");
|
2013-11-23 16:30:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
glfwMakeContextCurrent(window);
|
|
|
|
glfwSetKeyCallback(window, KeyCallback);
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
int fbWidth, fbHeight;
|
|
|
|
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
|
|
|
|
|
|
|
|
rlglInitGraphicsDevice(fbWidth, fbHeight);
|
2014-03-16 23:59:02 +04:00
|
|
|
|
|
|
|
LoadDefaultFont();
|
2013-11-23 16:30:54 +04:00
|
|
|
}
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sets Background Color
|
|
|
|
void ClearBackground(Color color)
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
if ((color.r != background.r) || (color.g != background.g) || (color.b != background.b) || (color.a != background.a))
|
|
|
|
{
|
|
|
|
rlClearColor(color.r, color.g, color.b, color.a);
|
|
|
|
|
|
|
|
background = color;
|
|
|
|
}
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Setup drawing canvas to start drawing
|
|
|
|
void BeginDrawing()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
currentTime = glfwGetTime(); // glfwGetTime() returns a 'double' containing the number of elapsed seconds since glfwInit() was called
|
|
|
|
updateTime = currentTime - previousTime;
|
|
|
|
previousTime = currentTime;
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
rlClearScreenBuffers();
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
|
|
|
|
|
|
|
|
//#ifdef USE_OPENGL_11
|
|
|
|
// rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL
|
|
|
|
// NOTE: Not required with OpenGL 3.3+
|
|
|
|
//#endif
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// End canvas drawing and Swap Buffers (Double Buffering)
|
|
|
|
void EndDrawing()
|
|
|
|
{
|
2013-12-19 15:08:06 +04:00
|
|
|
if (customCursor && cursorOnScreen) DrawTexture(cursor, GetMouseX(), GetMouseY(), WHITE);
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
//------------------------------------------------------
|
2014-04-09 22:25:26 +04:00
|
|
|
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
|
2014-03-25 15:40:35 +04:00
|
|
|
rlglDraw(); // Draw Buffers
|
|
|
|
#endif
|
|
|
|
//------------------------------------------------------
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
glfwSwapBuffers(window); // Swap back and front buffers
|
|
|
|
glfwPollEvents(); // Register keyboard/mouse events
|
|
|
|
|
2014-04-19 18:36:49 +04:00
|
|
|
UpdateMusicStream(); // NOTE: Function checks if music is enabled
|
2014-04-09 22:25:26 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
currentTime = glfwGetTime();
|
|
|
|
drawTime = currentTime - previousTime;
|
|
|
|
previousTime = currentTime;
|
|
|
|
|
|
|
|
frameTime = updateTime + drawTime;
|
|
|
|
|
|
|
|
double extraTime = 0;
|
|
|
|
|
|
|
|
while (frameTime < targetTime)
|
|
|
|
{
|
|
|
|
// Implement a delay
|
|
|
|
currentTime = glfwGetTime();
|
|
|
|
extraTime = currentTime - previousTime;
|
|
|
|
previousTime = currentTime;
|
|
|
|
frameTime += extraTime;
|
|
|
|
}
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initializes 3D mode for drawing (Camera setup)
|
|
|
|
void Begin3dMode(Camera camera)
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
//------------------------------------------------------
|
2014-04-09 22:25:26 +04:00
|
|
|
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
|
2014-03-25 15:40:35 +04:00
|
|
|
rlglDraw(); // Draw Buffers
|
|
|
|
#endif
|
|
|
|
//------------------------------------------------------
|
|
|
|
|
|
|
|
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection
|
|
|
|
rlLoadIdentity(); // Reset current matrix (PROJECTION)
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2014-03-16 23:59:02 +04:00
|
|
|
// Setup perspective projection
|
|
|
|
float aspect = (GLfloat)windowWidth/(GLfloat)windowHeight;
|
|
|
|
double top = 0.1f*tan(45.0f*PI / 360.0);
|
|
|
|
double right = top*aspect;
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
rlFrustum(-right, right, -top, top, 0.1f, 100.0f);
|
2014-03-16 23:59:02 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix
|
|
|
|
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
// Setup Camera view
|
|
|
|
Matrix matLookAt = MatrixLookAt(camera.position, camera.target, camera.up);
|
|
|
|
rlMultMatrixf(GetMatrixVector(matLookAt)); // Multiply MODELVIEW matrix by view matrix (camera)
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ends 3D mode and returns to default 2D orthographic mode
|
|
|
|
void End3dMode()
|
|
|
|
{
|
2014-03-25 15:40:35 +04:00
|
|
|
//------------------------------------------------------
|
2014-04-09 22:25:26 +04:00
|
|
|
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
|
2014-03-25 15:40:35 +04:00
|
|
|
rlglDraw(); // Draw Buffers
|
|
|
|
#endif
|
|
|
|
//------------------------------------------------------
|
|
|
|
|
|
|
|
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
|
|
|
|
rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
rlMatrixMode(RL_MODELVIEW); // Get back to modelview matrix
|
|
|
|
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
|
2013-11-23 16:30:54 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
//rlTranslatef(0.375, 0.375, 0); // HACK to ensure pixel-perfect drawing on OpenGL (after exiting 3D mode)
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set target FPS for the game
|
|
|
|
void SetTargetFPS(int fps)
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
targetTime = 1 / (float)fps;
|
|
|
|
|
2014-04-09 22:25:26 +04:00
|
|
|
TraceLog(INFO, "Target time per frame: %02.03f milliseconds", (float)targetTime*1000);
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns current FPS
|
|
|
|
float GetFPS()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
return (1/(float)frameTime);
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns time in seconds for one frame
|
|
|
|
float GetFrameTime()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
// As we are operating quite a lot with frameTime, it could be no stable
|
|
|
|
// so we round it before before passing around to be used
|
|
|
|
// NOTE: There are still problems with high framerates (>500fps)
|
|
|
|
double roundedFrameTime = round(frameTime*10000) / 10000;
|
|
|
|
|
|
|
|
return (float)roundedFrameTime; // Time in seconds to run a frame
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a Color struct from hexadecimal value
|
|
|
|
Color GetColor(int hexValue)
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
Color color;
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
color.r = (unsigned char)(hexValue >> 24) & 0xFF;
|
|
|
|
color.g = (unsigned char)(hexValue >> 16) & 0xFF;
|
|
|
|
color.b = (unsigned char)(hexValue >> 8) & 0xFF;
|
|
|
|
color.a = (unsigned char)hexValue & 0xFF;
|
|
|
|
|
|
|
|
return color;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns hexadecimal value for a Color
|
|
|
|
int GetHexValue(Color color)
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
return ((color.a << 24) + (color.r << 16) + (color.g << 8) + color.b);
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
2013-12-19 15:08:06 +04:00
|
|
|
// Returns a random value between min and max (both included)
|
|
|
|
int GetRandomValue(int min, int max)
|
|
|
|
{
|
2014-01-07 19:53:57 +04:00
|
|
|
if (min > max)
|
|
|
|
{
|
|
|
|
int tmp = max;
|
|
|
|
max = min;
|
|
|
|
min = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rand()%(abs(max-min)+1) + min);
|
2013-12-19 15:08:06 +04:00
|
|
|
}
|
|
|
|
|
2014-01-23 15:36:18 +04:00
|
|
|
// Fades color by a percentadge
|
|
|
|
Color Fade(Color color, float alpha)
|
|
|
|
{
|
|
|
|
if (alpha < 0.0) alpha = 0.0;
|
|
|
|
else if (alpha > 1.0) alpha = 1.0;
|
|
|
|
|
|
|
|
return (Color){color.r, color.g, color.b, color.a*alpha};
|
|
|
|
}
|
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
2013-11-28 22:59:56 +04:00
|
|
|
// Detect if a key has been pressed once
|
2013-11-19 02:38:44 +04:00
|
|
|
bool IsKeyPressed(int key)
|
2013-11-28 22:59:56 +04:00
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
bool pressed = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
|
|
|
currentKeyState[key] = IsKeyDown(key);
|
|
|
|
|
|
|
|
if (currentKeyState[key] != previousKeyState[key])
|
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
if (currentKeyState[key]) pressed = true;
|
2013-11-28 22:59:56 +04:00
|
|
|
previousKeyState[key] = currentKeyState[key];
|
|
|
|
}
|
2014-04-09 22:25:26 +04:00
|
|
|
else pressed = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
2014-04-09 22:25:26 +04:00
|
|
|
return pressed;
|
2013-11-28 22:59:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Detect if a key is being pressed (key held down)
|
|
|
|
bool IsKeyDown(int key)
|
2013-11-19 02:38:44 +04:00
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
if (glfwGetKey(window, key) == GLFW_PRESS) return true;
|
|
|
|
else return false;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
2013-11-28 22:59:56 +04:00
|
|
|
// Detect if a key has been released once
|
2013-11-19 02:38:44 +04:00
|
|
|
bool IsKeyReleased(int key)
|
2013-11-28 22:59:56 +04:00
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
bool released = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
|
|
|
currentKeyState[key] = IsKeyUp(key);
|
|
|
|
|
|
|
|
if (currentKeyState[key] != previousKeyState[key])
|
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
if (currentKeyState[key]) released = true;
|
2013-11-28 22:59:56 +04:00
|
|
|
previousKeyState[key] = currentKeyState[key];
|
|
|
|
}
|
2014-04-09 22:25:26 +04:00
|
|
|
else released = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
2014-04-09 22:25:26 +04:00
|
|
|
return released;
|
2013-11-28 22:59:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Detect if a key is NOT being pressed (key not held down)
|
|
|
|
bool IsKeyUp(int key)
|
2013-11-19 02:38:44 +04:00
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
if (glfwGetKey(window, key) == GLFW_RELEASE) return true;
|
|
|
|
else return false;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
2013-11-28 22:59:56 +04:00
|
|
|
// Detect if a mouse button has been pressed once
|
2013-11-19 02:38:44 +04:00
|
|
|
bool IsMouseButtonPressed(int button)
|
2013-11-28 22:59:56 +04:00
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
bool pressed = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
|
|
|
currentMouseState[button] = IsMouseButtonDown(button);
|
|
|
|
|
|
|
|
if (currentMouseState[button] != previousMouseState[button])
|
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
if (currentMouseState[button]) pressed = true;
|
2013-11-28 22:59:56 +04:00
|
|
|
previousMouseState[button] = currentMouseState[button];
|
|
|
|
}
|
2014-04-09 22:25:26 +04:00
|
|
|
else pressed = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
2014-04-09 22:25:26 +04:00
|
|
|
return pressed;
|
2013-11-28 22:59:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Detect if a mouse button is being pressed
|
|
|
|
bool IsMouseButtonDown(int button)
|
2013-11-19 02:38:44 +04:00
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
if (glfwGetMouseButton(window, button) == GLFW_PRESS) return true;
|
|
|
|
else return false;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
2013-11-28 22:59:56 +04:00
|
|
|
// Detect if a mouse button has been released once
|
2013-11-19 02:38:44 +04:00
|
|
|
bool IsMouseButtonReleased(int button)
|
2013-11-28 22:59:56 +04:00
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
bool released = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
|
|
|
currentMouseState[button] = IsMouseButtonUp(button);
|
|
|
|
|
|
|
|
if (currentMouseState[button] != previousMouseState[button])
|
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
if (currentMouseState[button]) released = true;
|
2013-11-28 22:59:56 +04:00
|
|
|
previousMouseState[button] = currentMouseState[button];
|
|
|
|
}
|
2014-04-09 22:25:26 +04:00
|
|
|
else released = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
2014-04-09 22:25:26 +04:00
|
|
|
return released;
|
2013-11-28 22:59:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Detect if a mouse button is NOT being pressed
|
|
|
|
bool IsMouseButtonUp(int button)
|
2013-11-19 02:38:44 +04:00
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
if (glfwGetMouseButton(window, button) == GLFW_RELEASE) return true;
|
|
|
|
else return false;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns mouse position X
|
|
|
|
int GetMouseX()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
double mouseX;
|
|
|
|
double mouseY;
|
|
|
|
|
|
|
|
glfwGetCursorPos(window, &mouseX, &mouseY);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
return (int)mouseX;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns mouse position Y
|
|
|
|
int GetMouseY()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
double mouseX;
|
|
|
|
double mouseY;
|
|
|
|
|
|
|
|
glfwGetCursorPos(window, &mouseX, &mouseY);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
return (int)mouseY;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns mouse position XY
|
|
|
|
Vector2 GetMousePosition()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
double mouseX;
|
|
|
|
double mouseY;
|
|
|
|
|
|
|
|
glfwGetCursorPos(window, &mouseX, &mouseY);
|
|
|
|
|
|
|
|
Vector2 position = { (float)mouseX, (float)mouseY };
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
return position;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
// Returns mouse wheel movement Y
|
|
|
|
int GetMouseWheelMove()
|
|
|
|
{
|
|
|
|
previousMouseWheelY = currentMouseWheelY;
|
|
|
|
|
|
|
|
currentMouseWheelY = 0;
|
|
|
|
|
|
|
|
return previousMouseWheelY;
|
|
|
|
}
|
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
// Detect if a gamepad is available
|
|
|
|
bool IsGamepadAvailable(int gamepad)
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
int result = glfwJoystickPresent(gamepad);
|
|
|
|
|
|
|
|
if (result == 1) return true;
|
|
|
|
else return false;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return axis movement vector for a gamepad
|
|
|
|
Vector2 GetGamepadMovement(int gamepad)
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
Vector2 vec = { 0, 0 };
|
|
|
|
|
|
|
|
const float *axes;
|
2013-11-19 02:38:44 +04:00
|
|
|
int axisCount;
|
2013-11-23 16:30:54 +04:00
|
|
|
|
|
|
|
axes = glfwGetJoystickAxes(gamepad, &axisCount);
|
|
|
|
|
|
|
|
if (axisCount >= 2)
|
|
|
|
{
|
|
|
|
vec.x = axes[0]; // Left joystick X
|
|
|
|
vec.y = axes[1]; // Left joystick Y
|
|
|
|
|
|
|
|
//vec.x = axes[2]; // Right joystick X
|
|
|
|
//vec.x = axes[3]; // Right joystick Y
|
|
|
|
}
|
|
|
|
|
|
|
|
return vec;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Detect if a gamepad button is being pressed
|
|
|
|
bool IsGamepadButtonPressed(int gamepad, int button)
|
2013-11-28 22:59:56 +04:00
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
bool pressed = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
|
|
|
currentGamepadState[button] = IsGamepadButtonDown(gamepad, button);
|
|
|
|
|
|
|
|
if (currentGamepadState[button] != previousGamepadState[button])
|
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
if (currentGamepadState[button]) pressed = true;
|
2013-11-28 22:59:56 +04:00
|
|
|
previousGamepadState[button] = currentGamepadState[button];
|
|
|
|
}
|
2014-04-09 22:25:26 +04:00
|
|
|
else pressed = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
2014-04-09 22:25:26 +04:00
|
|
|
return pressed;
|
2013-11-28 22:59:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsGamepadButtonDown(int gamepad, int button)
|
2013-11-19 02:38:44 +04:00
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
const unsigned char* buttons;
|
|
|
|
int buttonsCount;
|
|
|
|
|
|
|
|
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
|
|
|
|
|
2014-03-16 23:59:02 +04:00
|
|
|
if ((buttons != NULL) && (buttons[button] == GLFW_PRESS))
|
2013-11-23 16:30:54 +04:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else return false;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Detect if a gamepad button is NOT being pressed
|
|
|
|
bool IsGamepadButtonReleased(int gamepad, int button)
|
2013-11-28 22:59:56 +04:00
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
bool released = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
|
|
|
currentGamepadState[button] = IsGamepadButtonUp(gamepad, button);
|
|
|
|
|
|
|
|
if (currentGamepadState[button] != previousGamepadState[button])
|
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
if (currentGamepadState[button]) released = true;
|
2013-11-28 22:59:56 +04:00
|
|
|
previousGamepadState[button] = currentGamepadState[button];
|
|
|
|
}
|
2014-04-09 22:25:26 +04:00
|
|
|
else released = false;
|
2013-11-28 22:59:56 +04:00
|
|
|
|
2014-04-09 22:25:26 +04:00
|
|
|
return released;
|
2013-11-28 22:59:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsGamepadButtonUp(int gamepad, int button)
|
2013-11-19 02:38:44 +04:00
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
const unsigned char* buttons;
|
|
|
|
int buttonsCount;
|
|
|
|
|
|
|
|
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
|
|
|
|
|
2014-03-16 23:59:02 +04:00
|
|
|
if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE))
|
2013-11-23 16:30:54 +04:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else return false;
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Module specific Functions Definition
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// GLFW3 Error Callback, runs on GLFW3 error
|
|
|
|
static void ErrorCallback(int error, const char *description)
|
|
|
|
{
|
2014-04-09 22:25:26 +04:00
|
|
|
TraceLog(WARNING, "GLFW3 Error: %s", description);
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
2014-01-29 00:21:29 +04:00
|
|
|
// GLFW3 Srolling Callback, runs on mouse wheel
|
|
|
|
static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
|
|
|
{
|
|
|
|
currentMouseWheelY = (int)yoffset;
|
|
|
|
}
|
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
// GLFW3 Keyboard Callback, runs on key pressed
|
|
|
|
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
|
|
|
{
|
2013-12-19 15:08:06 +04:00
|
|
|
if (key == exitKey && action == GLFW_PRESS)
|
2013-11-23 16:30:54 +04:00
|
|
|
{
|
|
|
|
glfwSetWindowShouldClose(window, GL_TRUE);
|
|
|
|
|
|
|
|
// NOTE: Before closing window, while loop must be left!
|
|
|
|
}
|
|
|
|
else if (key == GLFW_KEY_F11 && action == GLFW_PRESS)
|
|
|
|
{
|
|
|
|
ToggleFullscreen();
|
|
|
|
}
|
|
|
|
else if (key == GLFW_KEY_F12 && action == GLFW_PRESS)
|
|
|
|
{
|
|
|
|
TakeScreenshot();
|
|
|
|
}
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
2013-12-19 15:08:06 +04:00
|
|
|
static void CursorEnterCallback(GLFWwindow* window, int enter)
|
|
|
|
{
|
|
|
|
if (enter == GL_TRUE) cursorOnScreen = true;
|
|
|
|
else cursorOnScreen = false;
|
|
|
|
}
|
|
|
|
|
2013-11-19 02:38:44 +04:00
|
|
|
// GLFW3 WindowSize Callback, runs when window is resized
|
|
|
|
static void WindowSizeCallback(GLFWwindow* window, int width, int height)
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
int fbWidth, fbHeight;
|
|
|
|
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
|
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
// If window is resized, graphics device is re-initialized
|
|
|
|
// NOTE: Aspect ratio does not change, so, image can be deformed
|
|
|
|
rlglInitGraphicsDevice(fbWidth, fbHeight);
|
2013-11-19 02:38:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Takes a bitmap (BMP) screenshot and saves it in the same folder as executable
|
|
|
|
static void TakeScreenshot()
|
|
|
|
{
|
2013-11-23 16:30:54 +04:00
|
|
|
static int shotNum = 0; // Screenshot number, increments every screenshot take during program execution
|
2014-03-25 15:40:35 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
char buffer[20]; // Buffer to store file name
|
2014-03-25 15:40:35 +04:00
|
|
|
int fbWidth, fbHeight; // Frame buffer width and height
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
unsigned char *imgData = rlglReadScreenPixels(fbWidth, fbHeight);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2014-01-23 15:36:18 +04:00
|
|
|
sprintf(buffer, "screenshot%03i.png", shotNum);
|
2013-11-19 02:38:44 +04:00
|
|
|
|
2014-03-25 15:40:35 +04:00
|
|
|
WritePNG(buffer, imgData, fbWidth, fbHeight);
|
|
|
|
|
|
|
|
free(imgData);
|
|
|
|
|
2013-11-23 16:30:54 +04:00
|
|
|
shotNum++;
|
2014-04-19 18:36:49 +04:00
|
|
|
|
|
|
|
TraceLog(INFO, "[%s] Screenshot taken!", buffer);
|
2013-12-19 15:08:06 +04:00
|
|
|
}
|