Rotate targetting reticule to mob. Add pivot point

Notion of pivot point now for rotating, i.e. the anchor point at which
rotations are applied. Rotating the reticule is done by using inverse
trigonometry, namely atan2f.
This commit is contained in:
Doyle Thai 2016-07-23 21:26:15 +10:00
parent 358f850a2c
commit a43102ee26
6 changed files with 95 additions and 63 deletions

Binary file not shown.

View File

@ -147,7 +147,7 @@ INTERNAL void updateAndRenderDebugStack(Renderer *renderer, MemoryArena *arena,
v4 color = V4(0, 0, 0, 1); v4 color = V4(0, 0, 0, 1);
renderer_staticString(renderer, arena, &GLOBAL_debug.font, renderer_staticString(renderer, arena, &GLOBAL_debug.font,
GLOBAL_debug.debugStrings[i], GLOBAL_debug.debugStrings[i],
GLOBAL_debug.currStringP, rotate, color); GLOBAL_debug.currStringP, V2(0, 0), rotate, color);
GLOBAL_debug.currStringP.y -= (0.9f * GLOBAL_debug.stringLineGap); GLOBAL_debug.currStringP.y -= (0.9f * GLOBAL_debug.stringLineGap);
} }
@ -179,7 +179,7 @@ INTERNAL void renderConsole(Renderer *renderer, MemoryArena *arena)
v4 color = V4(0, 0, 0, 1); v4 color = V4(0, 0, 0, 1);
renderer_staticString(renderer, arena, &GLOBAL_debug.font, renderer_staticString(renderer, arena, &GLOBAL_debug.font,
GLOBAL_debug.console[i], consoleStrP, GLOBAL_debug.console[i], consoleStrP,
rotate, color); V2(0, 0), rotate, color);
consoleStrP.y -= (0.9f * GLOBAL_debug.stringLineGap); consoleStrP.y -= (0.9f * GLOBAL_debug.stringLineGap);
} }
} }
@ -218,7 +218,7 @@ void debug_drawUi(GameState *state, f32 dt)
v2 strPos = V2((renderer->size.w * 0.5f) - (strLenInPixels * 0.5f), v2 strPos = V2((renderer->size.w * 0.5f) - (strLenInPixels * 0.5f),
renderer->size.h - 300.0f); renderer->size.h - 300.0f);
renderer_staticString(&state->renderer, &state->arena, font, battleStr, renderer_staticString(&state->renderer, &state->arena, font, battleStr,
strPos, 0, color); strPos, V2(0, 0), 0, color);
} }
for (i32 i = 0; i < world->freeEntityIndex; i++) for (i32 i = 0; i < world->freeEntityIndex; i++)
@ -257,7 +257,7 @@ void debug_drawUi(GameState *state, f32 dt)
strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y; strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y;
renderer_string(&state->renderer, &state->arena, cameraBounds, font, renderer_string(&state->renderer, &state->arena, cameraBounds, font,
debugString, strPos, 0, color); debugString, strPos, V2(0, 0), 0, color);
f32 stringLineGap = 1.1f * asset_getVFontSpacing(font->metrics); f32 stringLineGap = 1.1f * asset_getVFontSpacing(font->metrics);
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
@ -266,14 +266,14 @@ void debug_drawUi(GameState *state, f32 dt)
snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f", snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f",
entity->pos.x, entity->pos.y); entity->pos.x, entity->pos.y);
renderer_string(&state->renderer, &state->arena, cameraBounds, font, renderer_string(&state->renderer, &state->arena, cameraBounds, font,
entityPosStr, strPos, 0, color); entityPosStr, strPos, V2(0, 0), 0, color);
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
char entityIDStr[32]; char entityIDStr[32];
snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entity->id, snprintf(entityIDStr, ARRAY_COUNT(entityIDStr), "ID: %4d/%d", entity->id,
world->uniqueIdAccumulator-1); world->uniqueIdAccumulator-1);
renderer_string(&state->renderer, &state->arena, cameraBounds, font, renderer_string(&state->renderer, &state->arena, cameraBounds, font,
entityIDStr, strPos, 0, color); entityIDStr, strPos, V2(0, 0), 0, color);
if (entity->stats) if (entity->stats)
{ {
@ -282,27 +282,27 @@ void debug_drawUi(GameState *state, f32 dt)
snprintf(entityHealth, ARRAY_COUNT(entityHealth), "HP: %3.0f/%3.0f", snprintf(entityHealth, ARRAY_COUNT(entityHealth), "HP: %3.0f/%3.0f",
entity->stats->health, entity->stats->maxHealth); entity->stats->health, entity->stats->maxHealth);
renderer_string(&state->renderer, &state->arena, cameraBounds, renderer_string(&state->renderer, &state->arena, cameraBounds,
font, entityHealth, strPos, 0, color); font, entityHealth, strPos, V2(0, 0), 0, color);
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
char entityTimer[32]; char entityTimer[32];
snprintf(entityTimer, ARRAY_COUNT(entityTimer), "ATB: %3.0f/%3.0f", snprintf(entityTimer, ARRAY_COUNT(entityTimer), "ATB: %3.0f/%3.0f",
entity->stats->actionTimer, entity->stats->actionRate); entity->stats->actionTimer, entity->stats->actionRate);
renderer_string(&state->renderer, &state->arena, cameraBounds, renderer_string(&state->renderer, &state->arena, cameraBounds,
font, entityTimer, strPos, 0, color); font, entityTimer, strPos, V2(0, 0), 0, color);
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
char entityIdTarget[32]; char entityIdTarget[32];
snprintf(entityIdTarget, ARRAY_COUNT(entityIdTarget), snprintf(entityIdTarget, ARRAY_COUNT(entityIdTarget),
"Targetting ID: %d", entity->stats->entityIdToAttack); "Targetting ID: %d", entity->stats->entityIdToAttack);
renderer_string(&state->renderer, &state->arena, cameraBounds, renderer_string(&state->renderer, &state->arena, cameraBounds,
font, entityIdTarget, strPos, 0, color); font, entityIdTarget, strPos, V2(0, 0), 0, color);
} }
strPos.y -= GLOBAL_debug.stringLineGap; strPos.y -= GLOBAL_debug.stringLineGap;
char *entityStateStr = debug_entitystate_string(entity->state); char *entityStateStr = debug_entitystate_string(entity->state);
renderer_string(&state->renderer, &state->arena, cameraBounds, font, renderer_string(&state->renderer, &state->arena, cameraBounds, font,
entityStateStr, strPos, 0, color); entityStateStr, strPos, V2(0, 0), 0, color);
} }
} }

View File

@ -87,20 +87,16 @@ createDefaultTexQuad(Renderer *renderer, RenderTex renderTex)
return result; return result;
} }
INTERNAL void renderObject(Renderer *renderer, v2 pos, v2 size, f32 rotate, INTERNAL void renderObject(Renderer *renderer, v2 pos, v2 size, v2 pivotPoint,
v4 color, Texture *tex) f32 rotate, v4 color, Texture *tex)
{ {
mat4 transMatrix = mat4_translate(pos.x, pos.y, 0.0f); mat4 transMatrix = mat4_translate(pos.x, pos.y, 0.0f);
// NOTE(doyle): Rotate from the center of the object, not its' origin (i.e. // NOTE(doyle): Rotate from pivot point of the object, (0, 0) is top left
// top left) mat4 rotateMatrix = mat4_translate(pivotPoint.x, pivotPoint.y, 0.0f);
mat4 rotateMatrix = mat4_translate((size.x * 0.5f), (size.y * 0.5f), 0.0f);
rotateMatrix = mat4_mul(rotateMatrix, mat4_rotate(rotate, 0.0f, 0.0f, 1.0f)); rotateMatrix = mat4_mul(rotateMatrix, mat4_rotate(rotate, 0.0f, 0.0f, 1.0f));
rotateMatrix = mat4_mul(rotateMatrix, mat4_translate((size.x * -0.5f), (size.y * -0.5f), 0.0f)); rotateMatrix = mat4_mul(rotateMatrix, mat4_translate(-pivotPoint.x, -pivotPoint.y, 0.0f));
// NOTE(doyle): We draw everything as a unit square in OGL. Scale it to size // NOTE(doyle): We draw everything as a unit square in OGL. Scale it to size
// TODO(doyle): We should have a notion of hitbox size and texture size
// we're going to render so we can draw textures that may be bigger than the
// entity, (slightly) but keep a consistent bounding box
mat4 scaleMatrix = mat4_scale(size.x, size.y, 1.0f); mat4 scaleMatrix = mat4_scale(size.x, size.y, 1.0f);
mat4 model = mat4_mul(transMatrix, mat4_mul(rotateMatrix, scaleMatrix)); mat4 model = mat4_mul(transMatrix, mat4_mul(rotateMatrix, scaleMatrix));
@ -140,7 +136,7 @@ INTERNAL void renderObject(Renderer *renderer, v2 pos, v2 size, f32 rotate,
} }
void renderer_rect(Renderer *const renderer, v4 cameraBounds, v2 pos, v2 size, void renderer_rect(Renderer *const renderer, v4 cameraBounds, v2 pos, v2 size,
f32 rotate, RenderTex renderTex, v4 color) v2 pivotPoint, f32 rotate, RenderTex renderTex, v4 color)
{ {
RenderQuad quad = createDefaultTexQuad(renderer, renderTex); RenderQuad quad = createDefaultTexQuad(renderer, renderTex);
updateBufferObject(renderer, &quad, 1); updateBufferObject(renderer, &quad, 1);
@ -148,13 +144,14 @@ void renderer_rect(Renderer *const renderer, v4 cameraBounds, v2 pos, v2 size,
// NOTE(doyle): Get the origin of cameraBounds in world space, bottom left // NOTE(doyle): Get the origin of cameraBounds in world space, bottom left
v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w); v2 offsetFromCamOrigin = V2(cameraBounds.x, cameraBounds.w);
v2 rectRelativeToCamera = v2_sub(pos, offsetFromCamOrigin); v2 rectRelativeToCamera = v2_sub(pos, offsetFromCamOrigin);
renderObject(renderer, rectRelativeToCamera, size, rotate, color, renderObject(renderer, rectRelativeToCamera, size, pivotPoint, rotate,
renderTex.tex); color, renderTex.tex);
} }
void renderer_string(Renderer *const renderer, MemoryArena *arena, void renderer_string(Renderer *const renderer, MemoryArena *arena,
v4 cameraBounds, Font *const font, v4 cameraBounds, Font *const font,
const char *const string, v2 pos, f32 rotate, v4 color) const char *const string, v2 pos, v2 pivotPoint,
f32 rotate, v4 color)
{ {
i32 strLen = common_strlen(string); i32 strLen = common_strlen(string);
// TODO(doyle): Scale, not too important .. but rudimentary infrastructure // TODO(doyle): Scale, not too important .. but rudimentary infrastructure
@ -208,14 +205,14 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena,
// relative to the window size, hence we also render at the origin since // relative to the window size, hence we also render at the origin since
// we're rendering a window sized buffer // we're rendering a window sized buffer
updateBufferObject(renderer, stringQuads, quadIndex); updateBufferObject(renderer, stringQuads, quadIndex);
renderObject(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color, renderObject(renderer, V2(0.0f, 0.0f), renderer->size, pivotPoint,
font->tex); rotate, color, font->tex);
PLATFORM_MEM_FREE(arena, stringQuads, strLen * sizeof(RenderQuad)); PLATFORM_MEM_FREE(arena, stringQuads, strLen * sizeof(RenderQuad));
} }
} }
void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity,
f32 rotate, v4 color) v2 pivotPoint, f32 rotate, v4 color)
{ {
// TODO(doyle): Batch into render groups // TODO(doyle): Batch into render groups
@ -247,6 +244,6 @@ void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity,
v2 entityRelativeToCamera = v2_sub(entity->pos, offsetFromCamOrigin); v2 entityRelativeToCamera = v2_sub(entity->pos, offsetFromCamOrigin);
renderObject(renderer, entityRelativeToCamera, entity->renderSize, renderObject(renderer, entityRelativeToCamera, entity->renderSize,
rotate, color, entity->tex); pivotPoint, rotate, color, entity->tex);
} }
} }

View File

@ -1022,7 +1022,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
*/ */
updateEntityAnim(entity, dt); updateEntityAnim(entity, dt);
/* Calculate region to render */ /* Calculate region to render */
renderer_entity(renderer, cameraBounds, entity, 0, V4(1, 1, 1, 1)); renderer_entity(renderer, cameraBounds, entity, V2(0, 0), 0, V4(1, 1, 1, 1));
} }
// TODO(doyle): Dead hero not accounted for here // TODO(doyle): Dead hero not accounted for here
@ -1060,8 +1060,8 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
V2(10.0f, (renderer->size.h * 0.5f) - (0.5f * heroAvatarSize.h)); V2(10.0f, (renderer->size.h * 0.5f) - (0.5f * heroAvatarSize.h));
RenderTex heroRenderTex = {hero->tex, heroAvatarTexRect}; RenderTex heroRenderTex = {hero->tex, heroAvatarTexRect};
renderer_staticRect(renderer, heroAvatarP, heroAvatarSize, 0, heroRenderTex, renderer_staticRect(renderer, heroAvatarP, heroAvatarSize, V2(0, 0), 0,
V4(1, 1, 1, 1)); heroRenderTex, V4(1, 1, 1, 1));
char heroAvatarStr[20]; char heroAvatarStr[20];
snprintf(heroAvatarStr, ARRAY_COUNT(heroAvatarStr), "HP: %3.0f/%3.0f", snprintf(heroAvatarStr, ARRAY_COUNT(heroAvatarStr), "HP: %3.0f/%3.0f",
@ -1070,36 +1070,42 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr)); CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr));
v2 strPos = V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarSize.h)); v2 strPos = V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarSize.h));
renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr, renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr,
strPos, 0, V4(0, 0, 1, 1)); strPos, V2(0, 0), 0, V4(0, 0, 1, 1));
#ifdef DENGINE_DEBUG
ASSERT(world->numEntitiesInBattle != 1);
#endif
if (world->numEntitiesInBattle > 1)
{
for (i32 i = 0; i < world->maxEntities; i++) for (i32 i = 0; i < world->maxEntities; i++)
{ {
Entity entity = world->entities[i]; Entity *entity = &world->entities[i];
if (entity.id == hero->id) continue; if (entity->id == hero->id)
continue;
if (entity->state == entitystate_attack ||
f32 distance = v2_magnitude(hero->pos, entity.pos); entity->state == entitystate_battle)
if (entity.state == entitystate_battle)
{ {
Texture *emptyTex = v2 difference = v2_sub(entity->pos, hero->pos);
asset_getTexture(assetManager, texlist_empty); f32 angle = math_atan2f(difference.y, difference.x);
v2 heroCenter = f32 angleDegrees = RADIANS_TO_DEGREES(angle);
v2_add(hero->pos, v2_scale(hero->hitboxSize, 0.5f));
RenderTex renderTex = {emptyTex, V4(0, 1, 1, 0)};
renderer_rect(&state->renderer, cameraBounds, heroCenter,
V2(distance, 5.0f), 0, renderTex,
V4(1, 0, 0, 0.5f));
}
}
}
Texture *emptyTex = asset_getTexture(assetManager, texlist_empty);
v2 heroCenter = v2_add(hero->pos, v2_scale(hero->hitboxSize, 0.5f));
RenderTex renderTex = {emptyTex, V4(0, 1, 1, 0)};
f32 distance = v2_magnitude(hero->pos, entity->pos);
renderer_rect(&state->renderer, cameraBounds, heroCenter,
V2(distance, 2.0f), V2(0, 0), angle, renderTex,
V4(1, 0, 0, 1.0f));
}
}
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
renderer_rect(&state->renderer, cameraBounds, V2(500, 500), V2(100, 2.0f),
V2(0, 0), DEGREES_TO_RADIANS(0.0f), renderTex,
V4(0, 0, 1, 1.0f));
renderer_rect(&state->renderer, cameraBounds, V2(500, 500), V2(100, 2.0f),
V2(0, 0), DEGREES_TO_RADIANS(5.0f), renderTex,
V4(0, 0, 1, 1.0f));
renderer_rect(&state->renderer, cameraBounds, V2(500, 500), V2(100, 2.0f),
V2(0, 0), DEGREES_TO_RADIANS(90.0f), renderTex,
V4(0, 0, 1, 1.0f));
debug_drawUi(state, dt); debug_drawUi(state, dt);
#endif #endif
} }

View File

@ -8,8 +8,21 @@
#define SQUARED(x) (x * x) #define SQUARED(x) (x * x)
#define ABS(x) ((x) > 0 ? (x) : -(x)) #define ABS(x) ((x) > 0 ? (x) : -(x))
#define DEGREES_TO_RADIANS(x) (x * (MATH_PI / 180.0f)) #define DEGREES_TO_RADIANS(x) (x * (MATH_PI / 180.0f))
#define RADIANS_TO_DEGREES(x) (x * (180.0f / MATH_PI))
#define SQRT(x) (sqrtf(x)) #define SQRT(x) (sqrtf(x))
INTERNAL inline f32 math_acosf(f32 a)
{
f32 result = acosf(a);
return result;
}
INTERNAL inline f32 math_atan2f(f32 y, f32 x)
{
f32 result = atan2f(y, x);
return result;
}
/* VECTORS */ /* VECTORS */
typedef union v2 typedef union v2
{ {
@ -120,12 +133,26 @@ DEFINE_VECTOR_FLOAT_MATH(2);
DEFINE_VECTOR_FLOAT_MATH(3); DEFINE_VECTOR_FLOAT_MATH(3);
DEFINE_VECTOR_FLOAT_MATH(4); DEFINE_VECTOR_FLOAT_MATH(4);
INTERNAL inline f32 v2_magnitude(const v2 a, const v2 b) INTERNAL inline f32 v2_lengthSq(const v2 a, const v2 b)
{ {
f32 x = b.x - a.x; f32 x = b.x - a.x;
f32 y = b.y - a.y; f32 y = b.y - a.y;
f32 inner = (SQUARED(x) + SQUARED(y)); f32 result = (SQUARED(x) + SQUARED(y));
f32 result = SQRT(inner); return result;
}
INTERNAL inline f32 v2_magnitude(const v2 a, const v2 b)
{
f32 lengthSq = v2_lengthSq(a, b);
f32 result = SQRT(lengthSq);
return result;
}
INTERNAL inline v2 v2_normalise(const v2 a)
{
f32 magnitude = v2_magnitude(V2(0, 0), a);
v2 result = V2(a.x, a.y);
result = v2_scale(a, 1 / magnitude);
return result; return result;
} }

View File

@ -27,30 +27,32 @@ typedef struct RenderTex
// TODO(doyle): Clean up lines // TODO(doyle): Clean up lines
// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); } // Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
void renderer_rect(Renderer *const renderer, v4 cameraBounds, v2 pos, v2 size, void renderer_rect(Renderer *const renderer, v4 cameraBounds, v2 pos, v2 size,
f32 rotate, RenderTex renderTex, v4 color); v2 pivotPoint, f32 rotate, RenderTex renderTex, v4 color);
inline void renderer_staticRect(Renderer *const renderer, v2 pos, v2 size, inline void renderer_staticRect(Renderer *const renderer, v2 pos, v2 size,
f32 rotate, RenderTex renderTex, v4 color) v2 pivotPoint, f32 rotate, RenderTex renderTex,
v4 color)
{ {
v4 staticCameraBounds = math_getRect(V2(0, 0), renderer->size); v4 staticCameraBounds = math_getRect(V2(0, 0), renderer->size);
renderer_rect(renderer, staticCameraBounds, pos, size, rotate, renderTex, renderer_rect(renderer, staticCameraBounds, pos, size, pivotPoint, rotate,
color); renderTex, color);
} }
void renderer_string(Renderer *const renderer, MemoryArena *arena, void renderer_string(Renderer *const renderer, MemoryArena *arena,
v4 cameraBounds, Font *const font, v4 cameraBounds, Font *const font,
const char *const string, v2 pos, f32 rotate, v4 color); const char *const string, v2 pos, v2 pivotPoint,
f32 rotate, v4 color);
inline void renderer_staticString(Renderer *const renderer, MemoryArena *arena, inline void renderer_staticString(Renderer *const renderer, MemoryArena *arena,
Font *const font, const char *const string, Font *const font, const char *const string,
v2 pos, f32 rotate, v4 color) v2 pos, v2 pivotPoint, f32 rotate, v4 color)
{ {
v4 staticCameraBounds = math_getRect(V2(0, 0), renderer->size); v4 staticCameraBounds = math_getRect(V2(0, 0), renderer->size);
renderer_string(renderer, arena, staticCameraBounds, font, string, pos, renderer_string(renderer, arena, staticCameraBounds, font, string, pos,
rotate, color); pivotPoint, rotate, color);
} }
void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity,
f32 rotate, v4 color); v2 pivotPoint, f32 rotate, v4 color);
#endif #endif