billboarding
parent
76dd148671
commit
082c485eeb
|
@ -98,6 +98,8 @@ void platform_get_block_realpos(float *x, float *y){
|
|||
entity_view *e = game_world_view_active_get_entity(cam.ent_id);
|
||||
if (!e) return;
|
||||
float zoom = renderer_zoom_get();
|
||||
mpos.x = screenWidth-mpos.x;
|
||||
mpos.y = screenHeight-mpos.y;
|
||||
mpos.x -= screenWidth/2.0f;
|
||||
mpos.y -= screenHeight/2.0f;
|
||||
cam.x += mpos.x*(1.0f/zoom);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <math.h>
|
||||
#include "platform/system.h"
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
#include "world/blocks.h"
|
||||
#include "models/assets.h"
|
||||
|
||||
|
@ -283,3 +284,257 @@ void DrawSpriteTextureEco(Texture2D texture, Vector3 position, float width, floa
|
|||
|
||||
rlSetTexture(0);
|
||||
}
|
||||
|
||||
static inline
|
||||
void Draw3DRectangle(Camera camera, float x, float y, float z, float w, float h, Color tint)
|
||||
{
|
||||
rlPushMatrix();
|
||||
|
||||
// get the camera view matrix
|
||||
Matrix mat = MatrixLookAt(camera.position, camera.target, camera.up);
|
||||
// peel off just the rotation
|
||||
Quaternion quat = QuaternionFromMatrix(mat);
|
||||
mat = QuaternionToMatrix(quat);
|
||||
|
||||
// apply just the rotation
|
||||
rlMultMatrixf(MatrixToFloat(mat));
|
||||
|
||||
Vector3 position = (Vector3){x,z,y};
|
||||
position = Vector3Transform(position, MatrixInvert(mat));
|
||||
rlTranslatef(position.x, position.y, position.z);
|
||||
|
||||
// draw the billboard
|
||||
float width = w / 2;
|
||||
float height = h / 2;
|
||||
|
||||
rlCheckRenderBatchLimit(6);
|
||||
|
||||
// draw quad
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||
// Front Face
|
||||
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
|
||||
rlVertex3f(-width, -height, 0); // Bottom Left Of The Texture and Quad
|
||||
rlVertex3f(+width, -height, 0); // Bottom Right Of The Texture and Quad
|
||||
rlVertex3f(+width, +height, 0); // Top Right Of The Texture and Quad
|
||||
rlVertex3f(-width, +height, 0); // Top Left Of The Texture and Quad
|
||||
|
||||
rlEnd();
|
||||
rlPopMatrix();
|
||||
}
|
||||
|
||||
static inline
|
||||
void Draw3DBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint)
|
||||
{
|
||||
rlPushMatrix();
|
||||
|
||||
// get the camera view matrix
|
||||
Matrix mat = MatrixLookAt(camera.position, camera.target, camera.up);
|
||||
// peel off just the rotation
|
||||
Quaternion quat = QuaternionFromMatrix(mat);
|
||||
mat = QuaternionToMatrix(quat);
|
||||
|
||||
// apply just the rotation
|
||||
rlMultMatrixf(MatrixToFloat(mat));
|
||||
|
||||
// translate backwards in the inverse rotated matrix to put the item where it goes in world space
|
||||
position = Vector3Transform(position, MatrixInvert(mat));
|
||||
rlTranslatef(position.x, position.y, position.z);
|
||||
|
||||
// draw the billboard
|
||||
float width = size.x / 2;
|
||||
float height = size.y / 2;
|
||||
|
||||
rlCheckRenderBatchLimit(6);
|
||||
|
||||
rlSetTexture(texture.id);
|
||||
|
||||
// draw quad
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||
// Front Face
|
||||
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
|
||||
|
||||
rlTexCoord2f((float)source.x / texture.width, (float)(source.y + source.height) / texture.height);
|
||||
rlVertex3f(-width, -height, 0); // Bottom Left Of The Texture and Quad
|
||||
|
||||
rlTexCoord2f((float)(source.x + source.width) / texture.width, (float)(source.y + source.height) / texture.height);
|
||||
rlVertex3f(+width, -height, 0); // Bottom Right Of The Texture and Quad
|
||||
|
||||
rlTexCoord2f((float)(source.x + source.width) / texture.width, (float)source.y / texture.height);
|
||||
rlVertex3f(+width, +height, 0); // Top Right Of The Texture and Quad
|
||||
|
||||
rlTexCoord2f((float)source.x / texture.width, (float)source.y / texture.height);
|
||||
rlVertex3f(-width, +height, 0); // Top Left Of The Texture and Quad
|
||||
|
||||
rlEnd();
|
||||
rlSetTexture(0);
|
||||
rlPopMatrix();
|
||||
}
|
||||
|
||||
static inline
|
||||
void Draw3DBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint)
|
||||
{
|
||||
Draw3DBillboardRec(camera, texture, (Rectangle){ 0,0,(float)texture.width,(float)texture.height }, position, (Vector2){ size,size }, tint);
|
||||
}
|
||||
|
||||
// Draw codepoint at specified position in 3D space
|
||||
static 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.glyphs[index].offsetX - font.glyphPadding)/(float)font.baseSize*scale;
|
||||
position.z += (float)(font.glyphs[index].offsetY - font.glyphPadding)/(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.glyphPadding, font.recs[index].y - (float)font.glyphPadding,
|
||||
font.recs[index].width + 2.0f*font.glyphPadding, font.recs[index].height + 2.0f*font.glyphPadding };
|
||||
|
||||
float width = (float)(font.recs[index].width + 2.0f*font.glyphPadding)/(float)font.baseSize*scale;
|
||||
float height = (float)(font.recs[index].height + 2.0f*font.glyphPadding)/(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;
|
||||
|
||||
rlCheckRenderBatchLimit(4 + 4*backface);
|
||||
rlSetTexture(font.texture.id);
|
||||
|
||||
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();
|
||||
|
||||
rlSetTexture(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a 2D text in 3D space
|
||||
static 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')
|
||||
{
|
||||
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.glyphs[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale;
|
||||
else textOffsetX += (float)(font.glyphs[index].advanceX + fontSpacing)/(float)font.baseSize*scale;
|
||||
}
|
||||
|
||||
i += codepointByteCount; // Move text bytes counter to next codepoint
|
||||
}
|
||||
}
|
||||
|
||||
// Measure a text in 3D. For some reason `MeasureTextEx()` just doesn't seem to work so i had to use this instead.
|
||||
static 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.glyphs[index].advanceX != 0) textWidth += (font.glyphs[index].advanceX+fontSpacing)/(float)font.baseSize*scale;
|
||||
else textWidth += (font.recs[index].width + font.glyphs[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;
|
||||
}
|
||||
|
|
|
@ -61,10 +61,10 @@ void platform_input() {
|
|||
{
|
||||
float x=0.0f, y=0.0f;
|
||||
uint8_t use, sprint, drop, ctrl, pick;
|
||||
if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) x += 1.0f;
|
||||
if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) x -= 1.0f;
|
||||
if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y += 1.0f;
|
||||
if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) y -= 1.0f;
|
||||
if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) x -= 1.0f;
|
||||
if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) x += 1.0f;
|
||||
if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y -= 1.0f;
|
||||
if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) y += 1.0f;
|
||||
|
||||
use = IsKeyPressed(KEY_SPACE);
|
||||
sprint = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
|
||||
|
@ -77,6 +77,8 @@ void platform_input() {
|
|||
mouse_pos.y /= screenHeight;
|
||||
mouse_pos.x -= 0.5f;
|
||||
mouse_pos.y -= 0.5f;
|
||||
mouse_pos.x = screenWidth - mouse_pos.x;
|
||||
mouse_pos.y = screenHeight - mouse_pos.y;
|
||||
mouse_pos = Vector2Normalize(mouse_pos);
|
||||
|
||||
if (game_get_kind() == GAMEKIND_SINGLE && IsMouseButtonDown(MOUSE_MIDDLE_BUTTON)) {
|
||||
|
|
|
@ -9,17 +9,18 @@ float zpl_lerp(float,float,float);
|
|||
float zpl_to_degrees(float);
|
||||
|
||||
void DrawNametag(const char* name, uint64_t key, entity_view *data, float x, float y) {
|
||||
float size = 16.f;
|
||||
float font_size = lerp(4.0f, 32.0f, 0.5f/1.0f);//(float)render_camera.zoom);
|
||||
float size = 72.f;
|
||||
float font_size = lerp(12.0f, 72.0f, 0.5f/1.0f);//(float)render_camera.zoom);
|
||||
float font_spacing = 1.1f;
|
||||
float title_bg_offset = 4;
|
||||
float fixed_title_offset = 8.f;
|
||||
float health = (data->hp / data->max_hp);
|
||||
const char *title = TextFormat("%s %llu", name, key);
|
||||
float title_w = MeasureTextEco(title, font_size, font_spacing);
|
||||
DrawRectangleEco(x-title_w/2.f-title_bg_offset/2.f, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(BLACK, data->tran_time));
|
||||
DrawRectangleEco(x-title_w/2.f-title_bg_offset/2.f, y-size-fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time));
|
||||
Draw3DRectangle(render_camera, x-title_w/2.f-title_bg_offset/2.f, y, size+font_size+fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(BLACK, data->tran_time));
|
||||
Draw3DRectangle(render_camera, x-title_w/2.f-title_bg_offset/2.f, y, size+fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time));
|
||||
DrawTextEco(title, x-title_w/2.f, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing);
|
||||
DrawText3D(GetFontDefault(), title, (Vector3){x-title_w/2.f, 64.f, y}, 24.f, 12.0f, 1.3f, true, WHITE);
|
||||
}
|
||||
|
||||
void DEBUG_draw_ground(uint64_t key, entity_view * data) {
|
||||
|
@ -40,7 +41,7 @@ void DEBUG_draw_ground(uint64_t key, entity_view * data) {
|
|||
tex.texture.height *= (int32_t)scale;
|
||||
// DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time));
|
||||
DrawCubeTexture(tex.texture, (Vector3){x+half_size, 0.0f, y+half_size}, size, 0.01f, size, WHITE);
|
||||
DrawCubeWires((Vector3){x, 0.f, y}, WORLD_BLOCK_SIZE*view->chunk_size, 66, WORLD_BLOCK_SIZE*view->chunk_size, BLUE);
|
||||
// DrawCubeWires((Vector3){x, 0.f, y}, WORLD_BLOCK_SIZE*view->chunk_size, 66, WORLD_BLOCK_SIZE*view->chunk_size, BLUE);
|
||||
|
||||
for (size_t ty = 0; ty < view->chunk_size; ty++) {
|
||||
for (size_t tx = 0; tx < view->chunk_size; tx++) {
|
||||
|
@ -97,6 +98,7 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
|
|||
float bl_size = (float)(view->chunk_size * WORLD_BLOCK_SIZE);
|
||||
float half_size = bl_size / 2.0f;
|
||||
float half_block_size = (float)(WORLD_BLOCK_SIZE >> 1);
|
||||
Texture2D sprite_tex = GetSpriteTexture2D(assets_find(data->asset));
|
||||
|
||||
switch (data->kind) {
|
||||
case EKIND_DEMO_NPC: {
|
||||
|
@ -136,11 +138,7 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
|
|||
float y = data->y - 32.f;
|
||||
// DrawTexturePro(GetSpriteTexture2D(assets_find(data->asset)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
|
||||
// DrawCubeTexture(GetSpriteTexture2D(assets_find(data->asset)), (Vector3){x + half_block_size, 32.0f, y + half_block_size}, 64, 0.01f, 64, WHITE);
|
||||
DrawSpriteTextureEco(GetSpriteTexture2D(assets_find(data->asset)), (Vector3){x + half_block_size, half_block_size/2, y + half_block_size}, 32, 0.01f, 32, WHITE);
|
||||
|
||||
if (data->asset == ASSET_BIG_TREE) {
|
||||
DrawSpriteTextureEco(GetSpriteTexture2D(assets_find(data->asset)), (Vector3){x + half_block_size, 150, y + half_block_size}, 300, 0.01f, 300, WHITE);
|
||||
}
|
||||
Draw3DBillboard(render_camera, sprite_tex, (Vector3){x + half_block_size, 32.0f, y + half_block_size}, 64.0f, WHITE);
|
||||
|
||||
if (data->quantity > 1) {
|
||||
DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f);
|
||||
|
@ -154,8 +152,7 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
|
|||
case EKIND_DEVICE: {
|
||||
float x = data->x - 32.f;
|
||||
float y = data->y - 32.f;
|
||||
// DrawTexturePro(GetSpriteTexture2D(assets_find(data->asset)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
|
||||
DrawSpriteTextureEco(GetSpriteTexture2D(assets_find(data->asset)), (Vector3){x + half_block_size, 32, y + half_block_size}, 64, 0.01f, 64, WHITE);
|
||||
Draw3DBillboard(render_camera, sprite_tex, (Vector3){x + half_block_size, 32.0f, y + half_block_size}, 64.0f, WHITE);
|
||||
|
||||
if (data->quantity > 1) {
|
||||
DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f);
|
||||
|
@ -207,8 +204,8 @@ void renderer_draw(void) {
|
|||
|
||||
camera game_camera = camera_get();
|
||||
#if 1
|
||||
render_camera.position = (Vector3){(float)game_camera.x, 260.0f*(10.0f-cam_zoom), (float)game_camera.y+50.0f*(10.0f-cam_zoom/2.0f)};
|
||||
render_camera.target = (Vector3){(float)game_camera.x, 0.0f, (float)game_camera.y};
|
||||
render_camera.position = (Vector3){(float)game_camera.x, 260.0f*(10.0f-cam_zoom)+30.0f, (float)game_camera.y-50.0f*(10.0f-cam_zoom/2.0f)};
|
||||
render_camera.target = (Vector3){(float)game_camera.x, 30.0f, (float)game_camera.y};
|
||||
#else
|
||||
UpdateCamera(&render_camera);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue