#pragma once #include "system.h" #include "raylib.h" #include "world/blocks.h" #include "assets.h" #define RAYLIB_NEW_RLGL #include "rlgl.h" static inline float lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; } static inline void DrawTextEco(const char *text, float posX, float posY, int fontSize, Color color, float spacing) { #if 1 // Check if default font has been loaded if (GetFontDefault().texture.id != 0) { Vector2 position = { (float)posX , (float)posY }; int defaultFontSize = 10; // Default Font chars height in pixel int new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing; DrawTextEx(GetFontDefault(), text, position, (float)fontSize , (float)new_spacing , color); } #endif } static inline int MeasureTextEco(const char *text, int fontSize, float spacing) { #if 1 Vector2 vec = { 0.0f, 0.0f }; // Check if default font has been loaded if (GetFontDefault().texture.id != 0) { int defaultFontSize = 10; // Default Font chars height in pixel int new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing; vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)new_spacing); } return (int)vec.x; #else return 0; #endif } static inline void DrawCircleEco(float centerX, float centerY, float radius, Color color) { DrawCircleV((Vector2){ (float)centerX , (float)centerY }, radius , color); } static inline void DrawRectangleEco(float posX, float posY, float width, float height, Color color) { DrawRectangleV((Vector2){ (float)posX , (float)posY }, (Vector2){ width , height }, color); } static inline Texture2D GetBlockImage(uint8_t id) { return *(Texture2D*)blocks_get_img(id); } static inline RenderTexture2D GetChunkTexture(uint64_t id) { RenderTexture2D *tex = (RenderTexture2D*)blocks_get_chunk_tex(id); if (!tex) return (RenderTexture2D){0}; return *tex; } static inline Texture2D GetSpriteTexture2D(uint16_t id) { return *(Texture2D*)assets_get_tex(id); } static inline Sound GetSound(uint16_t id) { return *(Sound*)assets_get_snd(id); } // Draw cube // NOTE: Cube position is the center position static inline void EcoDrawCube(Vector3 position, float width, float height, float length, float heading, Color color) { float x = 0.0f; float y = 0.0f; float z = 0.0f; rlCheckRenderBatchLimit(36); rlPushMatrix(); // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate) rlTranslatef(position.x, position.y, position.z); rlRotatef(heading, 0, 1, 0); //rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); // Front face rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right // Back face rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left // Top face rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right // Bottom face rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left // Right face rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left // Left face rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right rlEnd(); rlPopMatrix(); } // Draw codepoint at specified position in 3D space void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontSize, bool backface, Color tint) { // Character index position in sprite font // NOTE: In case a codepoint is not available in the font, index returned points to '?' int index = GetGlyphIndex(font, codepoint); float scale = fontSize/(float)font.baseSize; // Character destination rectangle on screen // NOTE: We consider charsPadding on drawing position.x += (float)(font.chars[index].offsetX - font.charsPadding)/(float)font.baseSize*scale; position.z += (float)(font.chars[index].offsetY - font.charsPadding)/(float)font.baseSize*scale; // Character source rectangle from font texture atlas // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding, font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding }; float width = (float)(font.recs[index].width + 2.0f*font.charsPadding)/(float)font.baseSize*scale; float height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale; if (font.texture.id > 0) { const float x = 0.0f; const float y = 0.0f; const float z = 0.0f; // normalized texture coordinates of the glyph inside the font texture (0.0f -> 1.0f) const float tx = srcRec.x/font.texture.width; const float ty = srcRec.y/font.texture.height; const float tw = (srcRec.x+srcRec.width)/font.texture.width; const float th = (srcRec.y+srcRec.height)/font.texture.height; { #if defined(RAYLIB_NEW_RLGL) } rlCheckRenderBatchLimit(4 + 4*backface); rlSetTexture(font.texture.id); #else if (rlCheckBufferLimit(4 + 4*backface)) rlglDraw(); rlEnableTexture(font.texture.id); #endif rlPushMatrix(); rlTranslatef(position.x, position.y, position.z); rlBegin(RL_QUADS); rlColor4ub(tint.r, tint.g, tint.b, tint.a); // Front Face rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Left Of The Texture and Quad rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Left Of The Texture and Quad rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Right Of The Texture and Quad rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Right Of The Texture and Quad if (backface) { // Back Face rlNormal3f(0.0f, -1.0f, 0.0f); // Normal Pointing Down rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Right Of The Texture and Quad rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Left Of The Texture and Quad rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Left Of The Texture and Quad rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Right Of The Texture and Quad } rlEnd(); rlPopMatrix(); #if defined(RAYLIB_NEW_RLGL) rlSetTexture(0); #else rlDisableTexture(); #endif } } void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, Color tint) { int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop float textOffsetY = 0.0f; // Offset between lines (on line break '\n') float textOffsetX = 0.0f; // Offset X to next character to draw float scale = fontSize/(float)font.baseSize; for (int i = 0; i < length;) { // Get next codepoint from byte string and glyph index in font int codepointByteCount = 0; int codepoint = GetCodepoint(&text[i], &codepointByteCount); int index = GetGlyphIndex(font, codepoint); // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // but we need to draw all of the bad bytes using the '?' symbol moving one byte if (codepoint == 0x3f) codepointByteCount = 1; if (codepoint == '\n') { // NOTE: Fixed line spacing of 1.5 line-height // TODO: Support custom line spacing defined by user textOffsetY += scale + lineSpacing/(float)font.baseSize*scale; textOffsetX = 0.0f; } else { if ((codepoint != ' ') && (codepoint != '\t')) { DrawTextCodepoint3D(font, codepoint, (Vector3){ position.x + textOffsetX, position.y, position.z + textOffsetY }, fontSize, backface, tint); } if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale; else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale; } i += codepointByteCount; // Move text bytes counter to next codepoint } } Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing) { int len = TextLength(text); int tempLen = 0; // Used to count longer text line num chars int lenCounter = 0; float tempTextWidth = 0.0f; // Used to count longer text line width float scale = fontSize/(float)font.baseSize; float textHeight = scale; float textWidth = 0.0f; int letter = 0; // Current character int index = 0; // Index position in sprite font for (int i = 0; i < len; i++) { lenCounter++; int next = 0; letter = GetCodepoint(&text[i], &next); index = GetGlyphIndex(font, letter); // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1 if (letter == 0x3f) next = 1; i += next - 1; if (letter != '\n') { if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale; else textWidth += (font.recs[index].width + font.chars[index].offsetX)/(float)font.baseSize*scale; } else { if (tempTextWidth < textWidth) tempTextWidth = textWidth; lenCounter = 0; textWidth = 0.0f; textHeight += scale + lineSpacing/(float)font.baseSize*scale; } if (tempLen < lenCounter) tempLen = lenCounter; } if (tempTextWidth < textWidth) tempTextWidth = textWidth; Vector3 vec = { 0 }; vec.x = tempTextWidth + (float)((tempLen - 1)*fontSpacing/(float)font.baseSize*scale); // Adds chars spacing to measure vec.y = 0.25f; vec.z = textHeight; return vec; } Color GenerateRandomColor(float s, float v) { const float Phi = 0.618033988749895f; // Golden ratio conjugate float h = GetRandomValue(0, 360); h = fmodf((h + h*Phi), 360.0f); return ColorFromHSV(h, s, v); }