From a68818e320cb90e2bbc772f65343cb79b78770ae Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 16 Mar 2014 20:59:02 +0100 Subject: [PATCH] Update to version 1.0.6 Check CHANGELOG for the list of changes in this release! --- CHANGELOG | 18 ++- release/win32-mingw/include/raylib.h | 17 ++- release/win32-mingw/lib/libraylib.a | Bin 170068 -> 174142 bytes src/core.c | 57 ++------- src/models.c | 185 ++++++++++++++++++++++----- src/raylib.h | 11 +- src/shapes.c | 16 ++- src/text.c | 59 ++++----- src/textures.c | 68 +++------- src/vector3.c | 2 +- tests/heightmap.png | Bin 0 -> 1362 bytes tests/test_billboard.c | 77 +++++++++++ tests/test_formattext.c | 62 +++++++++ tests/test_heightmap.c | 76 +++++++++++ tests/test_image_loading.c | 60 +++++++++ tests/test_mouse_wheel.c | 57 +++++++++ tests/test_random.c | 62 +++++++++ 17 files changed, 652 insertions(+), 175 deletions(-) create mode 100644 tests/heightmap.png create mode 100644 tests/test_billboard.c create mode 100644 tests/test_formattext.c create mode 100644 tests/test_heightmap.c create mode 100644 tests/test_image_loading.c create mode 100644 tests/test_mouse_wheel.c create mode 100644 tests/test_random.c diff --git a/CHANGELOG b/CHANGELOG index d07c4433e..cd4274d78 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,16 +1,32 @@ changelog --------- -Current Release: raylib 1.0.4 (January 2014) +Current Release: raylib 1.0.6 (March 2014) NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source. NOTE: Current Release includes all previous updates. +----------------------------------------------- +Release: raylib 1.0.6 (16 March 2014) +----------------------------------------------- +[core] Removed unused lighting-system code +[core] Removed SetPerspective() function, calculated directly +[core] Unload and reload default font on fullscreen toggle +[core] Corrected bug gamepad buttons checking if no gamepad available +[texture] DrawTextureV() - Added, to draw using Vector2 for position +[texture] LoadTexture() - Redesigned, now uses LoadImage() + CreateTexture() +[text] FormatText() - Corrected memory leak bug +[models] Added Matrix struct and related functions +[models] DrawBillboard() - Reviewed, now it works! +[models] DrawBillboardRec() - Reviewed, now it works! +[tests] Added folder with multiple tests for new functions + ----------------------------------------------- Update: raylib 1.0.5 (28 January 2014) ----------------------------------------------- [audio] LoadSound() - Corrected a bug, WAV file was not closed! [core] GetMouseWheelMove() - Added, check mouse wheel Y movement +[texture] CreateTexture2D() renamed to CreateTexture() [models] LoadHeightmap() - Added, Heightmap can be loaded as a Model [tool] rREM updated, now supports (partially) drag and drop of files diff --git a/release/win32-mingw/include/raylib.h b/release/win32-mingw/include/raylib.h index dff65ae6e..fd66819c3 100644 --- a/release/win32-mingw/include/raylib.h +++ b/release/win32-mingw/include/raylib.h @@ -1,6 +1,6 @@ /********************************************************************************************* * -* raylib 1.0.4 (www.raylib.com) +* raylib 1.0.6 (www.raylib.com) * * A simple and easy-to-use library to learn videogames programming * @@ -65,6 +65,7 @@ #define KEY_SPACE 32 #define KEY_ESCAPE 256 #define KEY_ENTER 257 +#define KEY_BACKSPACE 259 #define KEY_RIGHT 262 #define KEY_LEFT 263 #define KEY_DOWN 264 @@ -278,6 +279,7 @@ bool IsMouseButtonUp(int button); // Detect if a mouse but int GetMouseX(); // Returns mouse position X int GetMouseY(); // Returns mouse position Y Vector2 GetMousePosition(); // Returns mouse position XY +int GetMouseWheelMove(); // Returns mouse wheel movement Y bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available Vector2 GetGamepadMovement(int gamepad); // Return axis movement vector for a gamepad @@ -323,11 +325,12 @@ Image LoadImage(const char *fileName); Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource) Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) -Texture2D CreateTexture2D(Image image); // Create a Texture2D from Image data +Texture2D CreateTexture(Image image); // Create a Texture2D from Image data void UnloadImage(Image image); // Unload image from CPU memory (RAM) void UnloadTexture(Texture2D texture); // Unload texture from GPU memory void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D +void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -370,17 +373,13 @@ void DrawGizmo(Vector3 position, bool orbits); //------------------------------------------------------------------------------------ Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) //Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource) +Model LoadHeightmap(Image heightmap, float maxHeight); // Load a heightmap image as a 3d model void UnloadModel(Model model); // Unload 3d model from memory void DrawModel(Model model, Vector3 position, float scale, Color color); // Draw a model void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a textured model void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires - -// NOTE: The following functions work but are incomplete or require some revision -// DrawHeightmap is extremely inefficient and can impact performance up to 60% -void DrawBillboard(Camera camera, Texture2D texture, Vector3 basePos, float size, Color tint); // REVIEW: Draw a billboard (raylib 1.x) -void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 basePos, float size, Color tint); // REVIEW: Draw a billboard (raylib 1.x) -void DrawHeightmap(Image heightmap, Vector3 centerPos, Vector3 scale, Color color); // REVIEW: Draw heightmap using image map (raylib 1.x) -void DrawHeightmapEx(Image heightmap, Texture2D texture, Vector3 centerPos, Vector3 scale, Color tint); // REVIEW: Draw textured heightmap (raylib 1.x) +void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture +void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) diff --git a/release/win32-mingw/lib/libraylib.a b/release/win32-mingw/lib/libraylib.a index e0a1dd4dc7f8f00368ca17231d03865504064a3f..9df0a332bfb7edeb846fb8e74157754dbe83ac9d 100644 GIT binary patch delta 25498 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 delta 21324 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

(PH$GB9*QEPg$gk-Hu=;0_sT2la0tW7S>^-~n+4 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 ZfY&C07oKnb // Standard input / output lib #include // Declares malloc() and free() for memory management, rand() #include // Useful to initialize random seed -#include // Math related functions, tan() on SetPerspective +#include // Math related functions, tan() used to set perspective #include "vector3.h" // Basic Vector3 functions #include "utils.h" // WritePNG() function @@ -96,7 +96,6 @@ static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); static void CursorEnterCallback(GLFWwindow* window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area static void WindowSizeCallback(GLFWwindow* window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized static void CameraLookAt(Vector3 position, Vector3 target, Vector3 up); // Setup camera view (updates MODELVIEW matrix) -static void SetPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); // Setup view projection (updates PROJECTION matrix) static void TakeScreenshot(); // Takes a bitmap (BMP) screenshot and saves it in the same folder as executable //---------------------------------------------------------------------------------- @@ -147,14 +146,7 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons LoadDefaultFont(); - if (cursorImage != NULL) - { - // Load image as texture - cursor = LoadTexture(cursorImage); - - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - customCursor = true; - } + if (cursorImage != NULL) SetCustomCursor(cursorImage); srand(time(NULL)); // Initialize random seed } @@ -199,6 +191,8 @@ void ToggleFullscreen() { fullscreen = !fullscreen; // Toggle fullscreen flag + UnloadDefaultFont(); + glfwDestroyWindow(window); // Destroy the current window (we will recreate it!) // TODO: WARNING! All loaded resources are lost, we loose Context! @@ -217,6 +211,8 @@ void ToggleFullscreen() glfwSetKeyCallback(window, KeyCallback); InitGraphicsDevice(); + + LoadDefaultFont(); } } @@ -275,15 +271,18 @@ void EndDrawing() // Initializes 3D mode for drawing (Camera setup) void Begin3dMode(Camera camera) { - //glEnable(GL_LIGHTING); // TODO: Setup proper lighting system (raylib 1.x) - glMatrixMode(GL_PROJECTION); // Switch to projection matrix glPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection glLoadIdentity(); // Reset current matrix (PROJECTION) - SetPerspective(45.0f, (GLfloat)windowWidth/(GLfloat)windowHeight, 0.1f, 100.0f); // Setup perspective projection + // Setup perspective projection + float aspect = (GLfloat)windowWidth/(GLfloat)windowHeight; + double top = 0.1f*tan(45.0f*PI / 360.0); + double right = top*aspect; + glFrustum(-right, right, -top, top, 0.1f, 100.0f); + glMatrixMode(GL_MODELVIEW); // Switch back to modelview matrix glLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -300,8 +299,6 @@ void End3dMode() glLoadIdentity(); // Reset current matrix (MODELVIEW) glTranslatef(0.375, 0.375, 0); // HACK to ensure pixel-perfect drawing on OpenGL (after exiting 3D mode) - - //glDisable(GL_LIGHTING); // TODO: Setup proper lighting system (raylib 1.x) } // Set target FPS for the game @@ -570,7 +567,7 @@ bool IsGamepadButtonDown(int gamepad, int button) buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); - if (buttons[button] == GLFW_PRESS) + if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) { return true; } @@ -601,7 +598,7 @@ bool IsGamepadButtonUp(int gamepad, int button) buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); - if (buttons[button] == GLFW_RELEASE) + if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE)) { return true; } @@ -685,19 +682,6 @@ static void InitGraphicsDevice() glMatrixMode(GL_MODELVIEW); // Switch back to MODELVIEW matrix glLoadIdentity(); // Reset current matrix (MODELVIEW) - // TODO: Create an efficient Lighting System with proper functions (raylib 1.x) -/* - glEnable(GL_COLOR_MATERIAL); // Enable materials, causes some glMaterial atributes to track the current color (glColor)... - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // Material types and where to apply them - // NOTE: ONLY works with lighting; defines how light interacts with material - - glLightfv(GL_LIGHT1, GL_AMBIENT, lightAmbient); // Define ambient light color property - glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDiffuse); // Define diffuse light color property - glLightfv(GL_LIGHT1, GL_POSITION, lightPosition); // Define light position - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT1); // Enable light one (8 lights available at the same time) -*/ // TODO: Review all shapes/models are drawn CCW and enable backface culling //glEnable(GL_CULL_FACE); // Enable backface culling (Disabled by default) @@ -746,19 +730,6 @@ static void CameraLookAt(Vector3 position, Vector3 target, Vector3 up) glTranslatef(-position.x, -position.y, -position.z); // Translate eye to position } -// Setup view projection (updates PROJECTION matrix) -static void SetPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) -{ - double xmin, xmax, ymin, ymax; - - ymax = zNear * tan(fovy * PI / 360.0); - ymin = -ymax; - xmin = ymin * aspect; - xmax = ymax * aspect; - - glFrustum(xmin, xmax, ymin, ymax, zNear, zFar); -} - // Takes a bitmap (BMP) screenshot and saves it in the same folder as executable static void TakeScreenshot() { diff --git a/src/models.c b/src/models.c index 9edfb142f..e21ff8948 100644 --- a/src/models.c +++ b/src/models.c @@ -39,7 +39,14 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -// ... + +// Matrix type (OpenGL style 4x4 - right handed) +typedef struct Matrix { + float m0, m4, m8, m12; + float m1, m5, m9, m13; + float m2, m6, m10, m14; + float m3, m7, m11, m15; +} Matrix; //---------------------------------------------------------------------------------- // Global Variables Definition @@ -50,13 +57,15 @@ // Module specific Functions Declaration //---------------------------------------------------------------------------------- static float GetHeightValue(Color pixel); +static void MatrixTranspose(Matrix *mat); +static Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up); //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- // Draw cube -// NOTE: Cube position is de center position +// NOTE: Cube position is the center position void DrawCube(Vector3 position, float width, float height, float lenght, Color color) { glPushMatrix(); @@ -664,7 +673,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight) Model model; int mapX = heightmap.width; - int mapZ = heightmap.height; + int mapZ = heightmap.height; // NOTE: One vertex per pixel // TODO: Consider resolution when generating model data? @@ -681,11 +690,11 @@ Model LoadHeightmap(Image heightmap, float maxHeight) float scaleFactor = maxHeight/255; // TODO: Review scaleFactor calculation - for(int z = 0; z < mapZ-1; z++) - { - for(int x = 0; x < mapX-1; x++) - { - // Fill vertices array with data + for(int z = 0; z < mapZ-1; z++) + { + for(int x = 0; x < mapX-1; x++) + { + // Fill vertices array with data //---------------------------------------------------------- // one triangle - 3 vertex @@ -738,8 +747,8 @@ Model LoadHeightmap(Image heightmap, float maxHeight) vCounter += 6; trisCounter += 2; - } - } + } + } return model; } @@ -805,47 +814,165 @@ void DrawModelWires(Model model, Vector3 position, float scale, Color color) } // Draw a billboard -void DrawBillboard(Camera camera, Texture2D texture, Vector3 basePos, float size, Color tint) +void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint) { - // NOTE: Billboard size will represent the width, height maintains aspect ratio - Vector3 centerPos = { basePos.x, basePos.y + size * (float)texture.height/(float)texture.width/2, basePos.z }; + // NOTE: Billboard size will maintain texture aspect ratio, size will be billboard width Vector2 sizeRatio = { size, size * (float)texture.height/texture.width }; - Vector3 rotation = { 90, 0, 0 }; - // TODO: Calculate Y rotation to face always camera (use matrix) - // OPTION: Lock Y-axis + Matrix viewMatrix = MatrixLookAt(camera.position, camera.target, camera.up); + MatrixTranspose(&viewMatrix); + + Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 }; + Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 }; +/* + d-------c + | | + | * | + | | + a-------b +*/ + VectorScale(&right, sizeRatio.x/2); + VectorScale(&up, sizeRatio.y/2); + + Vector3 p1 = VectorAdd(right, up); + Vector3 p2 = VectorSubtract(right, up); + Vector3 a = VectorSubtract(center, p2); + Vector3 b = VectorAdd(center, p1); + Vector3 c = VectorAdd(center, p2); + Vector3 d = VectorSubtract(center, p1); + glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture.glId); - - DrawPlane(centerPos, sizeRatio, rotation, tint); // TODO: Review this function... + + glBegin(GL_QUADS); + glColor4ub(tint.r, tint.g, tint.b, tint.a); + glNormal3f(0.0f, 1.0f, 0.0f); + glTexCoord2f(0.0f, 0.0f); glVertex3f(a.x, a.y, a.z); + glTexCoord2f(1.0f, 0.0f); glVertex3f(b.x, b.y, b.z); + glTexCoord2f(1.0f, 1.0f); glVertex3f(c.x, c.y, c.z); + glTexCoord2f(0.0f, 1.0f); glVertex3f(d.x, d.y, d.z); + glEnd(); glDisable(GL_TEXTURE_2D); } // Draw a billboard (part of a texture defined by a rectangle) -void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 basePos, float size, Color tint) +void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint) { - // NOTE: Billboard size will represent the width, height maintains aspect ratio - //Vector3 centerPos = { basePos.x, basePos.y + size * (float)texture.height/(float)texture.width/2, basePos.z }; - //Vector2 sizeRatio = { size, size * (float)texture.height/texture.width }; - //Vector3 rotation = { 90, 0, 0 }; - - // TODO: Calculate Y rotation to face always camera (use matrix) - // OPTION: Lock Y-axis + // NOTE: Billboard size will maintain sourceRec aspect ratio, size will represent billboard width + Vector2 sizeRatio = { size, size * (float)sourceRec.height/sourceRec.width }; - glEnable(GL_TEXTURE_2D); + Matrix viewMatrix = MatrixLookAt(camera.position, camera.target, camera.up); + MatrixTranspose(&viewMatrix); + + Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 }; + Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 }; +/* + d-------c + | | + | * | + | | + a-------b +*/ + VectorScale(&right, sizeRatio.x/2); + VectorScale(&up, sizeRatio.y/2); + + Vector3 p1 = VectorAdd(right, up); + Vector3 p2 = VectorSubtract(right, up); + + Vector3 a = VectorSubtract(center, p2); + Vector3 b = VectorAdd(center, p1); + Vector3 c = VectorAdd(center, p2); + Vector3 d = VectorSubtract(center, p1); + + glEnable(GL_TEXTURE_2D); // Enable textures usage glBindTexture(GL_TEXTURE_2D, texture.glId); - // TODO: DrawPlane with correct textcoords for source rec. + glBegin(GL_QUADS); + glColor4ub(tint.r, tint.g, tint.b, tint.a); + + // Bottom-left corner for texture and quad + glTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height); + glVertex3f(a.x, a.y, a.z); + + // Bottom-right corner for texture and quad + glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); + glVertex3f(b.x, b.y, b.z); + + // Top-right corner for texture and quad + glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); + glVertex3f(c.x, c.y, c.z); + + // Top-left corner for texture and quad + glTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); + glVertex3f(d.x, d.y, d.z); + glEnd(); - glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_2D); // Disable textures usage } // Get current vertex y altitude (proportional to pixel colors in grayscale) static float GetHeightValue(Color pixel) { return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3); +} + +// Returns camera look-at matrix (view matrix) +static Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) +{ + Matrix result; + + Vector3 z = VectorSubtract(eye, target); + VectorNormalize(&z); + Vector3 x = VectorCrossProduct(up, z); + VectorNormalize(&x); + Vector3 y = VectorCrossProduct(z, x); + VectorNormalize(&y); + + result.m0 = x.x; + result.m1 = x.y; + result.m2 = x.z; + result.m3 = -((x.x * eye.x) + (x.y * eye.y) + (x.z * eye.z)); + result.m4 = y.x; + result.m5 = y.y; + result.m6 = y.z; + result.m7 = -((y.x * eye.x) + (y.y * eye.y) + (y.z * eye.z)); + result.m8 = z.x; + result.m9 = z.y; + result.m10 = z.z; + result.m11 = -((z.x * eye.x) + (z.y * eye.y) + (z.z * eye.z)); + result.m12 = 0; + result.m13 = 0; + result.m14 = 0; + result.m15 = 1; + + return result; +} + +// Transposes provided matrix +static void MatrixTranspose(Matrix *mat) +{ + Matrix temp; + + temp.m0 = mat->m0; + temp.m1 = mat->m4; + temp.m2 = mat->m8; + temp.m3 = mat->m12; + temp.m4 = mat->m1; + temp.m5 = mat->m5; + temp.m6 = mat->m9; + temp.m7 = mat->m13; + temp.m8 = mat->m2; + temp.m9 = mat->m6; + temp.m10 = mat->m10; + temp.m11 = mat->m14; + temp.m12 = mat->m3; + temp.m13 = mat->m7; + temp.m14 = mat->m11; + temp.m15 = mat->m15; + + *mat = temp; } \ No newline at end of file diff --git a/src/raylib.h b/src/raylib.h index 867b72182..fd66819c3 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1,6 +1,6 @@ /********************************************************************************************* * -* raylib 1.0.4 (www.raylib.com) +* raylib 1.0.6 (www.raylib.com) * * A simple and easy-to-use library to learn videogames programming * @@ -325,11 +325,12 @@ Image LoadImage(const char *fileName); Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource) Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) -Texture2D CreateTexture(Image image); // Create a Texture2D from Image data +Texture2D CreateTexture(Image image); // Create a Texture2D from Image data void UnloadImage(Image image); // Unload image from CPU memory (RAM) void UnloadTexture(Texture2D texture); // Unload texture from GPU memory void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D +void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters @@ -377,10 +378,8 @@ void UnloadModel(Model model); void DrawModel(Model model, Vector3 position, float scale, Color color); // Draw a model void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a textured model void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires - -// NOTE: The following functions work but are incomplete or require some revision -void DrawBillboard(Camera camera, Texture2D texture, Vector3 basePos, float size, Color tint); // REVIEW: Draw a billboard (raylib 1.x) -void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 basePos, float size, Color tint); // REVIEW: Draw a billboard (raylib 1.x) +void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture +void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) diff --git a/src/shapes.c b/src/shapes.c index b033cde99..07a73cad9 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -61,8 +61,16 @@ void DrawPixel(int posX, int posY, Color color) glColor4ub(color.r, color.g, color.b, color.a); glVertex2i(posX, posY); glEnd(); - - // NOTE: Alternative method to draw a pixel (point) + + // NOTE1: Alternative method to draw a pixel (GL_LINES) +/* + glBegin(GL_LINES); + glColor4ub(color.r, color.g, color.b, color.a); + glVertex2i(posX, posY); + glVertex2i(posX+1, posY+1); + glEnd(); +*/ + // NOTE2: Alternative method to draw a pixel (glPoint()) /* glEnable(GL_POINT_SMOOTH); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Deprecated on OGL 3.0 @@ -426,7 +434,7 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) if (rec1.x <= rec2.x) { if (rec1.y <= rec2.y) - { + { retRec.x = rec2.x; retRec.y = rec2.y; retRec.width = rec1.width - dxx; @@ -443,7 +451,7 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) else { if (rec1.y <= rec2.y) - { + { retRec.x = rec1.x; retRec.y = rec2.y; retRec.width = rec2.width - dxx; diff --git a/src/text.c b/src/text.c index f1070a031..492329c50 100644 --- a/src/text.c +++ b/src/text.c @@ -8,7 +8,7 @@ * stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) * * 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. * @@ -37,8 +37,9 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FIRST_CHAR 32 -#define MAX_FONTCHARS 128 +#define FONT_FIRST_CHAR 32 +#define MAX_FONTCHARS 128 +#define MAX_FORMATTEXT_LENGTH 50 #define BIT_CHECK(a,b) ((a) & (1<<(b))) @@ -125,7 +126,7 @@ extern void LoadDefaultFont() for (int i = 0; i < defaultFont.numChars; i++) { - defaultFont.charSet[i].value = FIRST_CHAR + i; + defaultFont.charSet[i].value = FONT_FIRST_CHAR + i; // First char is 32 defaultFont.charSet[i].x = currentPosX; defaultFont.charSet[i].y = charsDivisor + currentLine * (charsHeight + charsDivisor); defaultFont.charSet[i].w = charsWidth[i]; @@ -329,31 +330,26 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f; else scaleFactor = (float)fontSize / spriteFont.charSet[0].h; - glDisable(GL_LIGHTING); // When drawing text, disable LIGHTING glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, spriteFont.texture.glId); - glPushMatrix(); - - // Optimized to use one draw call per string - glBegin(GL_QUADS); - for(int i = 0; i < length; i++) - { - c = spriteFont.charSet[(int)text[i] - FIRST_CHAR]; - - glColor4ub(tint.r, tint.g, tint.b, tint.a); - glNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer - glTexCoord2f((float)c.x / spriteFont.texture.width, (float)c.y / spriteFont.texture.height); glVertex2f(positionX, position.y); - glTexCoord2f((float)c.x / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height); glVertex2f(positionX, position.y + (c.h) * scaleFactor); - glTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height); glVertex2f(positionX + (c.w) * scaleFactor, position.y + (c.h) * scaleFactor); - glTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)c.y / spriteFont.texture.height); glVertex2f(positionX + (c.w) * scaleFactor, position.y); - - positionX += ((spriteFont.charSet[(int)text[i] - FIRST_CHAR].w) * scaleFactor + spacing); - } - glEnd(); - - glPopMatrix(); + // Optimized to use one draw call per string + glBegin(GL_QUADS); + for(int i = 0; i < length; i++) + { + c = spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR]; + + glColor4ub(tint.r, tint.g, tint.b, tint.a); + glNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer + glTexCoord2f((float)c.x / spriteFont.texture.width, (float)c.y / spriteFont.texture.height); glVertex2f(positionX, position.y); + glTexCoord2f((float)c.x / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height); glVertex2f(positionX, position.y + (c.h) * scaleFactor); + glTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height); glVertex2f(positionX + (c.w) * scaleFactor, position.y + (c.h) * scaleFactor); + glTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)c.y / spriteFont.texture.height); glVertex2f(positionX + (c.w) * scaleFactor, position.y); + + positionX += ((spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w) * scaleFactor + spacing); + } + glEnd(); glDisable(GL_TEXTURE_2D); } @@ -361,16 +357,13 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f // Formatting of text with variables to 'embed' const char *FormatText(const char *text, ...) { - int length = strlen(text); - char *buffer = malloc(length + 20); // We add 20 extra characters, should be enough... :P - + static char buffer[MAX_FORMATTEXT_LENGTH]; + va_list args; va_start(args, text); vsprintf(buffer, text, args); // NOTE: We use vsprintf() defined in va_end(args); - - //strcat(buffer, "\0"); // We add a end-of-string mark at the end (not needed) - + return buffer; } @@ -393,7 +386,7 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int for (int i = 0; i < len; i++) { - textWidth += spriteFont.charSet[(int)text[i] - FIRST_CHAR].w; + textWidth += spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w; } if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f; @@ -491,7 +484,7 @@ static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Char while((xPosToRead < imgWidth) && !PixelIsMagenta((imgDataPixel[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*imgWidth + xPosToRead]))) { - tempCharSet[index].value = FIRST_CHAR + index; + tempCharSet[index].value = FONT_FIRST_CHAR + index; tempCharSet[index].x = xPosToRead; tempCharSet[index].y = lineSpacing + lineToRead * (charHeight + lineSpacing); tempCharSet[index].h = charHeight; diff --git a/src/textures.c b/src/textures.c index c0832477d..ca0492c4a 100644 --- a/src/textures.c +++ b/src/textures.c @@ -218,37 +218,11 @@ Image LoadImageFromRES(const char *rresName, int resId) Texture2D LoadTexture(const char *fileName) { Texture2D texture; - - int imgWidth; - int imgHeight; - int imgBpp; + Image image; - // NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...) - // Force loading to 4 components (RGBA) - byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); - - // Convert loaded data to OpenGL texture - //---------------------------------------- - GLuint id; - glGenTextures(1, &id); // Generate Pointer to the Texture - - glBindTexture(GL_TEXTURE_2D, id); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repead on x-axis - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repead on y-axis - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imgWidth, imgHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgData); - - // NOTE: Not using mipmappings (texture for 2D drawing) - // At this point we have the image converted to texture and uploaded to GPU - - stbi_image_free(imgData); // Now we can free loaded data from RAM memory - - texture.glId = id; - texture.width = imgWidth; - texture.height = imgHeight; + image = LoadImage(fileName); + texture = CreateTexture(image); + UnloadImage(image); return texture; } @@ -264,23 +238,6 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId) return texture; } -// Load an image as texture (and convert to POT with mipmaps) -Texture2D LoadTextureEx(const char *fileName, bool createPOT, bool mipmaps) -{ - Texture2D texture; - - // TODO: Load and image and convert to Power-Of-Two - // NOTE: Conversion could be done just adding extra space to image or by scaling image - // NOTE: If scaling image, be careful with scaling algorithm (aproximation, bilinear, bicubic...) - - // TODO: Generate all required mipmap levels from image and convert to testure (not that easy) - // NOTE: If using OpenGL 1.1, the only option is doing mipmap generation on CPU side (i.e. gluBuild2DMipmaps) - // NOTE: raylib tries to minimize external dependencies so, we are not using GLU - // NOTE: Re-implement some function similar to gluBuild2DMipmaps (not that easy...) - - return texture; -} - // Create a Texture2D from Image data // NOTE: Image is not unloaded, it should be done manually... Texture2D CreateTexture(Image image) @@ -294,11 +251,18 @@ Texture2D CreateTexture(Image image) glBindTexture(GL_TEXTURE_2D, id); + // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used! glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repead on x-axis glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repead on y-axis - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR + // Trilinear filtering + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate use of mipmaps (must be available) + //glGenerateMipmap(GL_TEXTURE_2D); // OpenGL 3.3! + + // Upload texture to GPU glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.pixels); // NOTE: Not using mipmappings (texture for 2D drawing) @@ -329,6 +293,12 @@ void DrawTexture(Texture2D texture, int posX, int posY, Color tint) DrawTextureEx(texture, (Vector2){ (float)posX, (float)posY}, 0, 1.0f, tint); } +// Draw a Texture2D with position defined as Vector2 +void DrawTextureV(Texture2D texture, Vector2 position, Color tint) +{ + DrawTextureEx(texture, position, 0, 1.0f, tint); +} + // Draw a Texture2D with extended parameters void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint) { diff --git a/src/vector3.c b/src/vector3.c index 378ab8779..6b0e1573d 100644 --- a/src/vector3.c +++ b/src/vector3.c @@ -25,7 +25,7 @@ #include "vector3.h" -#include +#include // Used for fabs(), sqrt() // Add two vectors Vector3 VectorAdd(Vector3 v1, Vector3 v2) diff --git a/tests/heightmap.png b/tests/heightmap.png new file mode 100644 index 0000000000000000000000000000000000000000..c17050fcc2dc470a46306ec1994a8e9b08e5458d GIT binary patch literal 1362 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4kiW$h6xih%orFLBuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztFe_w+M3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtB zi9%9pdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tSWK~ za#KqZ6)JLb@`|l0Y?Z*~TICg6frRyy6u?SKvTcwn`Gtf;oFf&jv zGt@IQHZeCh*HJJsFf`CNFw!?P(ls=+T7#d8;`MLTPi3R$GdIlgbLHwFq;OmQDX>KlDb#X~h zD#E>34K5C;EJ)Q4N-fSWElN%eN=;J+xv9X)xhOTUB)=#mKR*W+iUAqCZ=YFhOWkr zriR9jmd>s&hEA?72BzjPy)OC5rManjB{01y2)(8_^@0)tC@`#CQj0RnQd8WD@^cly z9=6KF?G_`P=0WwQ;C72KPQChe3O4$nXhn)^oJo?Xa8L{VVx_i460 zTUUQ=ek^%EJH9%JWy{QEl3cAx8zt<7Iv?;JuCSZ`!$m1@_0>~PH>F0-^>c6JV{3j` zAW@<<)k|%%LdLGUd-5XGiO_rZo<6hnpwMVefn9mG)Pmd`)1BGXs=aY* z!!ExxkqYQYIwc&hH~njstyJ%WEw^)B4W$+?571CxGg44dWH|J)MCe(C&Aju^D~>uz zJdK|H*y0FJuSd#{eg5@-K31r(PTs32RPtfVL^dtU$nBrcUpQoIZBUzQv~;EJhwLLx zW?O1G-t>K($+Po_$$cmv7GkITFTO2XnY}R1rQ1twu|dYKfKs#ByzR~l1QzIuakuK6 zI>9!