Files
GameLib/src/Entity.c
2023-09-24 21:15:57 +02:00

1026 lines
24 KiB
C

// Copyright (C) 2011-2014 Valeriano Alfonso Rodriguez (Kableado)
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "Anim.h"
#include "Draw.h"
#include "Util.h"
#include "Entity.h"
#define EntityIntFlag_UpdateLight 1
#define EntityIntFlag_UpdatedPos 2
#define EntityIntFlag_UpdatedColor 4
#define EntityIntFlag_UpdateColor 8
#define EntityIntFlag_UpdatedScale 16
/////////////////////////////
// Entity_New
//
//
Entity _free_entity = NULL;
Entity Entity_New() {
Entity e;
if (!_free_entity) {
// Allocate a big block of entities
int n = 1024, i;
TEntity *newEnts = malloc(sizeof(TEntity) * n);
for (i = 0; i < n; i++) {
if (i < (n - 1)) {
newEnts[i].next = &newEnts[i + 1];
} else {
newEnts[i].next = NULL;
}
}
_free_entity = newEnts;
}
e = _free_entity;
_free_entity = e->next;
e->base = NULL;
e->type = 0;
vec2_set(e->pos0, 0.0f, 0.0f);
vec2_set(e->pos, 0.0f, 0.0f);
e->flags = EntityFlag_Collision | EntityFlag_Overlap;
e->internalFlags = EntityIntFlag_UpdateColor;
e->zorder = 1;
e->sortYOffset = 0;
vec2_set(e->dir, 0.0f, 0.0f);
vec2_set(e->vel, 0.0f, 0.0f);
e->radius = 1.0f;
e->width = 1.0f;
e->height = 1.0f;
e->mass = 1.0f;
e->elast = 0.0f;
e->backFric_static = 0.0f;
e->backFric_dynamic = 0.0f;
e->fric_static = 0.0f;
e->fric_dynamic = 0.0f;
AnimPlay_SetImg(&e->anim, NULL);
e->color0[0] = e->color0[1] = e->color0[2] = e->color0[3] = 1.0f;
e->color[0] = e->color[1] = e->color[2] = e->color[3] = 1.0f;
e->light[0] = e->light[1] = e->light[2] = e->light[3] = 1.0f;
e->defaultColor[0] = e->defaultColor[1] = e->defaultColor[2] = e->defaultColor[3] = 1.0f;
e->scale0[0] = 1.0f;
e->scale0[1] = 1.0f;
e->scale[0] = 1.0f;
e->scale[1] = 1.0f;
e->oncopy = NULL;
e->oninit = NULL;
e->ondelete = NULL;
e->proc = NULL;
e->postproc = NULL;
e->collision = NULL;
e->overlap = NULL;
e->A = 0;
e->B = 0;
e->C = 0;
e->D = 0;
e->E = 0;
e->child = NULL;
e->next = NULL;
return (e);
}
/////////////////////////////
// Entity_Init
//
Entity Entity_Init(Entity e) {
if (e->oninit) {
e->oninit(e);
}
return (e);
}
/////////////////////////////
// Entity_Destroy
//
//
void Entity_Destroy(Entity e) {
if (e->ondelete) {
e->ondelete(e);
}
e->next = _free_entity;
_free_entity = e;
}
/////////////////////////////
// Entity_Copy
//
//
Entity Entity_Copy(Entity e) {
Entity n;
n = Entity_New();
n->base = e;
n->type = e->type;
vec2_set(n->pos, e->pos[0], e->pos[1]);
n->flags = e->flags;
n->internalFlags = e->internalFlags;
n->zorder = e->zorder;
n->sortYOffset = e->sortYOffset;
vec2_set(n->vel, e->vel[0], e->vel[1]);
n->radius = e->radius;
n->width = e->width;
n->height = e->height;
n->mass = e->mass;
n->elast = e->elast;
n->backFric_static = e->backFric_static;
n->backFric_dynamic = e->backFric_dynamic;
n->fric_static = e->fric_static;
n->fric_dynamic = e->fric_dynamic;
AnimPlay_Copy(&n->anim, &e->anim);
n->color0[0] = e->color0[0];
n->color0[1] = e->color0[1];
n->color0[2] = e->color0[2];
n->color0[3] = e->color0[3];
n->color[0] = e->color[0];
n->color[1] = e->color[1];
n->color[2] = e->color[2];
n->color[3] = e->color[3];
n->light[0] = e->light[0];
n->light[1] = e->light[1];
n->light[2] = e->light[2];
n->light[3] = e->light[3];
n->defaultColor[0] = e->defaultColor[0];
n->defaultColor[1] = e->defaultColor[1];
n->defaultColor[2] = e->defaultColor[2];
n->defaultColor[3] = e->defaultColor[3];
n->scale0[0] = e->scale[0];
n->scale0[1] = e->scale[1];
n->scale[0] = e->scale[0];
n->scale[1] = e->scale[1];
n->oncopy = e->oncopy;
n->oninit = e->oninit;
n->ondelete = e->ondelete;
n->proc = e->proc;
n->postproc = e->postproc;
n->collision = e->collision;
n->overlap = e->overlap;
n->A = e->A;
n->B = e->B;
n->C = e->C;
n->D = e->D;
n->E = e->E;
n->child = e->child;
Entity_CalcBBox(n);
// Call the copy event
if (n->oncopy) {
n->oncopy(n);
}
return (n);
}
/////////////////////////////
// Entity_CalcBBox
//
//
#define BBox_ExtraMargin 10
#define max(a, b) ((a) > (b) ? (a) : (b))
void Entity_CalcBBox(Entity e) {
float hHeight = (max(e->height, e->radius) / 2) + BBox_ExtraMargin;
float hWidth = (max(e->width, e->radius) / 2) + BBox_ExtraMargin;
if (e->vel[0] > 0) {
e->maxX = e->pos[0] + e->vel[0] + hWidth;
e->minX = e->pos[0] - hWidth;
} else {
e->minX = (e->pos[0] + e->vel[0]) - hWidth;
e->maxX = e->pos[0] + hWidth;
}
if (e->vel[1] > 0) {
e->maxY = e->pos[1] + e->vel[1] + hHeight;
e->minY = e->pos[1] - hHeight;
} else {
e->minY = (e->pos[1] + e->vel[1]) - hHeight;
e->maxY = e->pos[1] + hHeight;
}
}
/////////////////////////////
// Entity_BBoxIntersect
//
//
int Entity_BBoxIntersect(Entity ent1, Entity ent2) {
if (ent1->maxX >= ent2->minX && ent1->minX <= ent2->maxX && ent1->maxY >= ent2->minY && ent1->minY <= ent2->maxY) {
return (1);
}
return (0);
}
/////////////////////////////
// Entity_Draw
//
//
void Entity_Draw(Entity e, int x, int y, float f) {
vec2 fPos;
float scale[2];
if (e->internalFlags & EntityIntFlag_UpdatedColor) {
Draw_SetColor(
e->color0[0] - f * (e->color0[0] - e->color[0]),
e->color0[1] - f * (e->color0[1] - e->color[1]),
e->color0[2] - f * (e->color0[2] - e->color[2]),
e->color0[3] - f * (e->color0[3] - e->color[3]));
} else {
Draw_SetColor(e->color[0], e->color[1], e->color[2], e->color[3]);
}
if (e->internalFlags & EntityIntFlag_UpdatedScale) {
scale[0] = e->scale0[0] - f * (e->scale0[0] - e->scale[0]);
scale[1] = e->scale0[1] - f * (e->scale0[1] - e->scale[1]);
} else {
scale[0] = e->scale[0];
scale[1] = e->scale[1];
}
if (e->internalFlags & EntityIntFlag_UpdatedPos) {
vec2_interpol(fPos, e->pos0, e->pos, f);
AnimPlay_Draw(&e->anim, fPos[0] + x, fPos[1] + y, scale);
} else {
AnimPlay_Draw(&e->anim, e->pos[0] + x, e->pos[1] + y, scale);
}
}
/////////////////////////////
// Entity_IsVisible
//
//
int Entity_IsVisible(Entity e, int x, int y, int w, int h) {
int xmax, xmin;
int ymax, ymin;
int ih, iw;
AnimPlay_GetSize(&e->anim, &iw, &ih);
xmin = x - iw;
xmax = x + w + iw;
ymin = y - ih;
ymax = y + h + ih;
if (e->pos[0] < xmin || e->pos[0] > xmax || e->pos[1] < ymin || e->pos[1] > ymax) {
return (0);
}
return (1);
}
/////////////////////////////
// Entity_Process
//
//
void Entity_Process(Entity e, int ft) {
if (e->internalFlags & EntityIntFlag_UpdatedPos) {
vec2_copy(e->pos0, e->pos);
e->internalFlags &= ~EntityIntFlag_UpdatedPos;
}
if (e->internalFlags & EntityIntFlag_UpdatedScale) {
e->scale0[0] = e->scale[0];
e->scale0[1] = e->scale[1];
e->internalFlags &= ~EntityIntFlag_UpdatedScale;
}
if (e->internalFlags & EntityIntFlag_UpdatedColor) {
e->color0[0] = e->color[0];
e->color0[1] = e->color[1];
e->color0[2] = e->color[2];
e->color0[3] = e->color[3];
e->internalFlags &= ~EntityIntFlag_UpdatedColor;
}
// Launch method
if (e->proc) {
e->proc(e, ft);
}
}
/////////////////////////////
// Entity_PostProcess
//
//
void Entity_PostProcess(Entity e, int ft) {
float qlen, len;
// Determine if there is movement
qlen = vec2_dot(e->vel, e->vel);
if (qlen > 0.0f) {
// Update position
vec2_plus(e->pos, e->pos, e->vel);
// Apply friction
len = sqrtf(qlen);
if (len < e->backFric_static) {
// Stopped by static friction
vec2_set(e->vel, 0, 0);
} else {
// Apply dynamic friction
vec2_scale(e->vel, e->vel, 1.0f - (e->backFric_dynamic + (e->backFric_static / len)));
}
// Mark the update of the position.
vec2_copy(e->oldpos, e->pos);
e->internalFlags |= EntityIntFlag_UpdatedPos;
Entity_CalcBBox(e);
}
// Launch method
if (e->postproc) {
e->postproc(e, ft);
}
// Animate
AnimPlay_IncTime(&e->anim, ft);
}
/////////////////////////////
// CollisionInfo_New
//
//
CollisionInfo _free_collInfo = NULL;
CollisionInfo CollisionInfo_New(int responseType, Entity ent1, Entity ent2, float t, vec2 n, int applyFriction) {
CollisionInfo collInfo;
if (!_free_collInfo) {
collInfo = malloc(sizeof(TCollisionInfo));
} else {
collInfo = _free_collInfo;
_free_collInfo = collInfo->next;
}
collInfo->next = NULL;
collInfo->responseType = responseType;
collInfo->ent1 = ent1;
collInfo->ent2 = ent2;
collInfo->t = t;
vec2_copy(collInfo->n, n);
collInfo->applyFriction = applyFriction;
return collInfo;
}
/////////////////////////////
// CollisionInfo_Destroy
//
//
void CollisionInfo_Destroy(CollisionInfo *collInfoRef) {
if (collInfoRef == NULL || collInfoRef[0] == NULL) {
return;
}
CollisionInfo collInfo = collInfoRef[0];
CollisionInfo nextCollInfo;
while (collInfo != NULL) {
nextCollInfo = collInfo->next;
collInfo->next = _free_collInfo;
_free_collInfo = collInfo;
collInfo = nextCollInfo;
}
collInfoRef[0] = NULL;
}
/////////////////////////////
// CollisionInfo_Add
//
//
void CollisionInfo_Add(
CollisionInfo *collInfoRef, int responseType, Entity ent1, Entity ent2, float t, vec2 n, int applyFriction) {
if (collInfoRef == NULL) {
return;
}
CollisionInfo prevCollInfo = NULL;
CollisionInfo collInfo = collInfoRef[0];
CollisionInfo newCollInfo = CollisionInfo_New(responseType, ent1, ent2, t, n, applyFriction);
while (collInfo != NULL && collInfo->t < t) {
prevCollInfo = collInfo;
collInfo = collInfo->next;
}
if (prevCollInfo == NULL) {
collInfoRef[0] = newCollInfo;
} else {
prevCollInfo->next = newCollInfo;
}
newCollInfo->next = collInfo;
}
/////////////////////////////
// CollisionInfo_CheckRepetition
//
//
int CollisionInfo_CheckRepetition(CollisionInfo collInfo, Entity ent1, Entity ent2) {
while (collInfo != NULL) {
if ((collInfo->ent1 == ent1 && collInfo->ent2 == ent2) || (collInfo->ent1 == ent2 && collInfo->ent2 == ent1)) {
return (1);
}
collInfo = collInfo->next;
}
return (0);
}
/////////////////////////////
// Entity_CheckCollisions
//
//
int Entity_CheckCollision(Entity ent1, Entity ent2, CollisionInfo *collInfoRef) {
float t;
vec2 n;
vec2 vel;
int flags = ent1->flags | ent2->flags;
if (flags & EntityFlag_Block) {
// One of the entities is a block and none is a platform
Entity ent, ent_block;
float auxT, block_len;
vec2 auxN, p;
int applyFriction;
// Decide who is the block and who is the ent
if (ent1->mass <= 0.0f && ent2->mass > 0.0f) {
ent = ent2;
ent_block = ent1;
} else if (ent2->mass <= 0.0f && ent1->mass > 0.0f) {
ent = ent1;
ent_block = ent2;
} else {
// Two static or two dinamic entities?!?
return (0);
}
// Prepare some variables
t = 1.0f;
applyFriction = 1;
if (flags & EntityFlag_BlockTop) {
vec2_set(auxN, 0, -1);
vec2_scaleadd(p, ent_block->pos, auxN, (ent->height + ent_block->height) / 2);
block_len = ent_block->width + ent->width;
if (Intersect_RayEdge(ent->pos, ent->vel, auxN, p, block_len, &auxT)) {
if (auxT < t) {
vec2_copy(n, auxN);
t = auxT;
applyFriction = 1;
}
}
}
if (flags & EntityFlag_BlockBottom) {
vec2_set(auxN, 0, 1);
vec2_scaleadd(p, ent_block->pos, auxN, (ent->height + ent_block->height) / 2);
block_len = ent_block->width + ent->width;
if (Intersect_RayEdge(ent->pos, ent->vel, auxN, p, block_len, &auxT)) {
if (auxT < t) {
vec2_copy(n, auxN);
t = auxT;
applyFriction = 1;
}
}
}
if (flags & EntityFlag_BlockRight) {
vec2_set(auxN, 1, 0);
vec2_scaleadd(p, ent_block->pos, auxN, (ent->width + ent_block->width) / 2);
block_len = ent_block->height + ent->height;
if (Intersect_RayEdge(ent->pos, ent->vel, auxN, p, block_len, &auxT)) {
if (auxT < t) {
vec2_copy(n, auxN);
t = auxT;
applyFriction = 0;
}
}
}
if (flags & EntityFlag_BlockLeft) {
vec2_set(auxN, -1, 0);
vec2_scaleadd(p, ent_block->pos, auxN, (ent->width + ent_block->width) / 2);
block_len = ent_block->height + ent->height;
if (Intersect_RayEdge(ent->pos, ent->vel, auxN, p, block_len, &auxT)) {
if (auxT < t) {
vec2_copy(n, auxN);
t = auxT;
applyFriction = 0;
}
}
}
if (t < 1.0f) {
CollisionInfo_Add(collInfoRef, CollisionResponse_Line, ent, ent_block, t, n, applyFriction);
return (1);
}
return (0);
}
// Circle-Circle test from ent1
vec2_minus(vel, ent1->vel, ent2->vel);
if (Colision_CircleCircle(ent1->pos, ent1->radius, vel, ent2->pos, ent2->radius, &t, n)) {
CollisionInfo_Add(collInfoRef, CollisionResponse_Circle, ent1, ent2, t, n, 0);
return (1);
}
return (0);
}
/////////////////////////////
// Entity_CollisionResponseCircle
//
// Normal response to a collision between circles.
void Entity_CollisionResponseCircle(Entity b1, Entity b2, float t, vec2 n) {
float moment;
vec2 temp;
float elast;
if (b1->mass > 0.0f && b2->mass > 0.0f) {
// Calculate elasticity
elast = (b1->mass * b1->elast + b2->mass * b2->elast) / (b1->mass + b2->mass);
// Collision between two massed balls
moment = ((1.0f + elast) * b1->mass * b2->mass * (fabs(vec2_dot(b1->vel, n)) + fabs(vec2_dot(b2->vel, n)))) /
(b1->mass + b2->mass);
vec2_scale(temp, n, moment / b1->mass);
vec2_minus(b1->vel, b1->vel, temp);
Entity_CalcBBox(b1);
vec2_scale(temp, n, moment / b2->mass);
vec2_plus(b2->vel, b2->vel, temp);
Entity_CalcBBox(b2);
} else if (b1->mass > 0.0f && b2->mass <= 0.0f) {
// Collision between a massed ball and a fixed ball
moment = (1.0f + b1->elast) * (vec2_dot(b1->vel, n));
vec2_scale(temp, n, moment);
vec2_minus(b1->vel, b1->vel, temp);
Entity_CalcBBox(b1);
} else if (b1->mass <= 0.0f && b2->mass > 0.0f) {
// Collision between a massed ball and a fixed ball
// (imposible, but better safe)
moment = (1.0f + b2->elast) * (vec2_dot(b2->vel, n));
vec2_scale(temp, n, moment);
vec2_plus(b2->vel, b2->vel, temp);
Entity_CalcBBox(b2);
} else {
// Collision between 2 fixed balls
// (imposible, but better safe)
vec2_set(b1->vel, 0, 0);
Entity_CalcBBox(b1);
vec2_set(b2->vel, 0, 0);
Entity_CalcBBox(b2);
}
}
/////////////////////////////
// Entity_CollisionResponseLine
//
// Normal response to a collision with a line.
void Entity_CollisionResponseLine(Entity ent, Entity ent2, float t, vec2 norm, int applyFriction) {
vec2 pos2, vel2, velFric, intersection;
float dist, fric_static, fric_dynamic, fricLen;
// Calculate end position
vec2_scale(vel2, ent->vel, 1.0f - t);
dist = -vec2_dot(norm, vel2);
vec2_plus(pos2, ent->pos, ent->vel);
vec2_scaleadd(pos2, pos2, norm, dist);
// Calculate intersection
vec2_scaleadd(intersection, ent->pos, ent->vel, t);
if (applyFriction) {
// Calculate friction
fric_static = (ent->fric_static + ent2->fric_static) / 2;
fric_dynamic = (ent->fric_dynamic + ent2->fric_dynamic) / 2;
// Apply friction
vec2_minus(velFric, pos2, intersection);
fricLen = sqrtf(vec2_dot(velFric, velFric));
if (fricLen < fric_static) {
// Apply static friction
vec2_copy(pos2, intersection);
} else {
// Apply dynamic friction
if (fricLen > 0.0f) {
vec2_scaleadd(pos2, intersection, velFric, 1.0f - (fric_dynamic + (fric_static / fricLen)));
} else {
vec2_scaleadd(pos2, intersection, velFric, 1.0f - fric_dynamic);
}
}
}
// Apply to velocity
vec2_scaleadd(pos2, pos2, norm, 0.1f);
vec2_minus(ent->vel, pos2, ent->pos);
Entity_CalcBBox(ent);
}
/////////////////////////////
// Entity_CollisionInfoResponse
//
//
int Entity_CollisionInfoResponse(CollisionInfo collInfo) {
while (collInfo != NULL) {
// Handle colision
int response = 1;
int rc;
vec2 n1;
vec2 n2;
vec2_copy(n1, collInfo->n);
vec2_scale(n2, collInfo->n, -1.0f);
// Check the collision methods
if (collInfo->ent1->collision) {
rc = collInfo->ent1->collision(collInfo->ent1, collInfo->ent2, collInfo->t, n1);
if (rc == 0)
response = 0;
if (rc > 1)
response = 2;
}
if (collInfo->ent2->collision) {
rc = collInfo->ent2->collision(collInfo->ent2, collInfo->ent1, collInfo->t, n2);
if (rc == 0)
response = 0;
if (rc > 1)
response = 2;
}
// Collision response
if (response == 1) {
if (collInfo->responseType == CollisionResponse_Line) {
Entity_CollisionResponseLine(
collInfo->ent1, collInfo->ent2, collInfo->t, collInfo->n, collInfo->applyFriction);
} else if (collInfo->responseType == CollisionResponse_Circle) {
if (vec2_dot(collInfo->ent1->vel, collInfo->ent1->vel) >
vec2_dot(collInfo->ent2->vel, collInfo->ent2->vel)) {
Entity_CollisionResponseCircle(collInfo->ent1, collInfo->ent2, collInfo->t, n2);
} else {
Entity_CollisionResponseCircle(collInfo->ent2, collInfo->ent1, collInfo->t, n1);
}
}
return (1);
}
if (response == 2) {
return (1);
}
collInfo = collInfo->next;
}
return (0);
}
/////////////////////////////
// Entity_Overlaps
//
//
void Entity_Overlaps(Entity b1, Entity b2) {
vec2 len;
vec2_minus(len, b1->pos, b2->pos);
vec2_set(len, fabs(b1->pos[0] - b2->pos[0]), fabs(b1->pos[1] - b2->pos[1]));
if (b1->overlap) {
if (len[0] <= b1->radius && len[1] <= b1->radius) {
b1->overlap(b1, b2);
}
}
if (b2->overlap) {
if (len[0] <= b2->radius && len[1] <= b2->radius) {
b2->overlap(b2, b1);
}
}
}
/////////////////////////////
// Entity_GetPos
//
//
void Entity_GetPos(Entity e, vec2 pos) { vec2_copy(pos, e->pos); }
/////////////////////////////
// Entity_SetPos
//
//
void Entity_SetPos(Entity e, vec2 pos) {
vec2_copy(e->pos, pos);
vec2_copy(e->oldpos, pos);
vec2_copy(e->pos0, pos);
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_AddPos
//
//
void Entity_AddPos(Entity e, vec2 pos) {
vec2_plus(e->pos, e->pos, pos);
vec2_copy(e->oldpos, e->pos);
vec2_copy(e->pos0, e->pos);
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_UpdatePos
//
//
void Entity_UpdatePos(Entity e, vec2 pos) {
// Mark the update of the position.
vec2_copy(e->oldpos, e->pos);
e->internalFlags |= EntityIntFlag_UpdatedPos;
vec2_copy(e->pos, pos);
}
/////////////////////////////
// Entity_AddVel
//
void Entity_AddVel(Entity e, vec2 vel) {
vec2_plus(e->vel, e->vel, vel);
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_SetVel
//
void Entity_SetVel(Entity e, vec2 vel) {
vec2_copy(e->vel, vel);
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_SetVelH
//
void Entity_SetVelH(Entity e, float v) {
e->vel[0] = v;
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_SetVelV
//
void Entity_SetVelV(Entity e, float v) {
e->vel[1] = v;
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_AddVelLimit
//
//
void Entity_AddVelLimit(Entity e, vec2 vel, float limit) {
float vlen_orig, vlen;
vec2 dir, vel_temp;
// Normalize vel getting vel
vlen_orig = sqrtf(vec2_dot(vel, vel));
vec2_scale(dir, vel, 1.0f / vlen_orig);
// Limit velocity
vlen = vec2_dot(e->vel, dir);
if (vlen < limit) {
vlen = limit - vlen;
if (vlen > vlen_orig) {
vlen = vlen_orig;
}
vec2_scale(vel_temp, dir, vlen);
vec2_plus(e->vel, e->vel, vel_temp);
}
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_AddVelLimitH
//
void Entity_AddVelLimitH(Entity e, float v, float limit) {
e->vel[0] += v;
if (e->vel[0] > 0.0f) {
if (e->vel[0] > limit) {
e->vel[0] = limit;
}
} else {
if (e->vel[0] < -limit) {
e->vel[0] = -limit;
}
}
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_AddVelLimitH
//
void Entity_AddVelLimitV(Entity e, float v, float limit) {
e->vel[1] += v;
if (e->vel[1] > 0.0f) {
if (e->vel[1] > limit) {
e->vel[1] = limit;
}
} else {
if (e->vel[1] < -limit) {
e->vel[1] = -limit;
}
}
Entity_CalcBBox(e);
}
/////////////////////////////
// Entity_SetColor
//
//
void Entity_SetColor(Entity e, float r, float g, float b, float a) {
e->color[0] = r;
e->color[1] = g;
e->color[2] = b;
e->color[3] = a;
e->color0[0] = r;
e->color0[1] = g;
e->color0[2] = b;
e->color0[3] = a;
e->internalFlags &= ~EntityIntFlag_UpdatedColor;
}
/////////////////////////////
// Entity_AddColor
//
//
void Entity_AddColor(Entity e, float r, float g, float b, float a) {
e->color[0] += r;
if (e->color[0] > 1.0f)
e->color[0] = 1.0f;
e->color[1] += g;
if (e->color[1] > 1.0f)
e->color[1] = 1.0f;
e->color[2] += b;
if (e->color[2] > 1.0f)
e->color[2] = 1.0f;
e->color[3] += a;
if (e->color[3] > 1.0f)
e->color[3] = 1.0f;
e->internalFlags |= EntityIntFlag_UpdatedColor;
}
/////////////////////////////
// Entity_MultColor
//
//
void Entity_MultColor(Entity e, float r, float g, float b, float a) {
e->color[0] *= r;
e->color[1] *= g;
e->color[2] *= b;
e->color[3] *= a;
e->internalFlags |= EntityIntFlag_UpdatedColor;
}
/////////////////////////////
// Entity_SetLight
//
//
void Entity_SetLight(Entity e, float r, float g, float b, float rad) {
e->light[0] = r;
e->light[1] = g;
e->light[2] = b;
e->light[3] = rad;
if (!(e->flags & EntityFlag_Light)) {
e->internalFlags |= EntityIntFlag_UpdateLight;
}
}
/////////////////////////////
// Entity_SetDefaultColor
//
//
void Entity_SetDefaultColor(Entity e, float r, float g, float b, float a) {
e->defaultColor[0] = r;
e->defaultColor[1] = g;
e->defaultColor[2] = b;
e->defaultColor[3] = a;
}
/////////////////////////////
// Entity_SetScale
//
void Entity_SetScale(Entity e, float scale[2]) {
e->scale[0] = scale[0];
e->scale[1] = scale[1];
e->internalFlags |= EntityIntFlag_UpdatedScale;
}
/////////////////////////////
// Entity_GetScale
//
void Entity_GetScale(Entity e, float scale[2]) {
scale[0] = e->scale[0];
scale[1] = e->scale[1];
}
/////////////////////////////
// Entity_Iluminate
//
//
void Entity_Iluminate(Entity e, Entity *elist, int n) {
int i;
vec2 vdist;
float qdist, f;
float qrad;
if (e->flags & EntityFlag_Light) {
Entity_SetColor(e, e->defaultColor[0], e->defaultColor[1], e->defaultColor[2], e->defaultColor[3]);
return;
}
e->color[0] = e->light[0];
e->color[1] = e->light[1];
e->color[2] = e->light[2];
e->color[3] = e->color[3];
for (i = 0; i < n; i++) {
if (e == elist[i] || !(elist[i]->flags & EntityFlag_Light))
continue;
vec2_minus(vdist, e->pos, elist[i]->pos);
qdist = vec2_dot(vdist, vdist);
qrad = elist[i]->light[3] * elist[i]->light[3];
if (qdist < qrad) {
f = 1.0f - qdist / qrad;
Entity_AddColor(e, f * elist[i]->light[0], f * elist[i]->light[1], f * elist[i]->light[2], 0.0f);
}
}
Entity_MultColor(e, e->defaultColor[0], e->defaultColor[1], e->defaultColor[2], e->defaultColor[3]);
e->internalFlags &= ~EntityIntFlag_UpdateLight;
if (e->internalFlags & EntityIntFlag_UpdateColor) {
e->color0[0] = e->color[0];
e->color0[1] = e->color[1];
e->color0[2] = e->color[2];
e->color0[3] = e->color[3];
e->internalFlags &= ~EntityIntFlag_UpdateColor;
}
}
/////////////////////////////
// Entity_MarkUpdateLight
//
//
void Entity_MarkUpdateLight(Entity e, Entity *elist, int n) {
if (e->flags & EntityFlag_Light) {
int i;
vec2 max, min;
if (e->pos0[0] < e->oldpos[0]) {
min[0] = e->pos0[0] - e->light[3];
max[0] = e->oldpos[0] + e->light[3];
} else {
min[0] = e->oldpos[0] - e->light[3];
max[0] = e->pos0[0] + e->light[3];
}
if (e->pos0[1] < e->oldpos[1]) {
min[1] = e->pos0[1] - e->light[3];
max[1] = e->oldpos[1] + e->light[3];
} else {
min[1] = e->oldpos[1] - e->light[3];
max[1] = e->pos0[1] + e->light[3];
}
for (i = 0; i < n; i++) {
if (elist[i] != NULL && min[0] <= elist[i]->pos0[0] && max[0] >= elist[i]->pos0[0] &&
min[1] <= elist[i]->pos0[1] && max[1] >= elist[i]->pos0[1]) {
elist[i]->internalFlags |= EntityIntFlag_UpdateLight;
}
}
} else {
e->internalFlags |= EntityIntFlag_UpdateLight;
}
}
/////////////////////////////
// Entity_IsLight
//
int Entity_IsLight(Entity e) { return (e->flags & EntityFlag_Light); }
/////////////////////////////
// Entity_IsUpdateLight
//
int Entity_IsUpdateLight(Entity e) { return (e->internalFlags & EntityIntFlag_UpdateLight); }
/////////////////////////////
// Entity_IsMoving
//
int Entity_IsMoving(Entity e) { return (e->internalFlags & EntityIntFlag_UpdatedPos); }