Files
GameLib/GameLib.c
2012-01-08 00:00:00 +01:00

567 lines
10 KiB
C

// Copyright (C) 2011 Valeriano Alfonso Rodriguez (Kableado)
#include <math.h>
#include <SDL/SDL.h>
#include "Time.h"
#include "Util.h"
#include "Draw.h"
#include "Input.h"
#include "Audio.h"
#include "Anim.h"
#include "Entity.h"
#include "GameLib.h"
// Globals
int _running;
Entity **_entity=NULL;
int *_entity_flag=NULL;
int _n_entities=0;
int _n_entities_res=0;
int _entities_lock=0;
int _entities_compactate=0;
void (*_gameproc)()=NULL;
void (*_gamepostproc)()=NULL;
void (*_gamedraw)()=NULL;
int _ft;
int _game_size[2];
int _game_pos[2];
long long t_proc;
long long t_col;
long long t_over;
long long t_postproc;
long long t_draw;
int fproc_count;
int fdraw_count;
int gamelib_debug=0;
/////////////////////////////
// GameLib_Init
//
// Initializes the game.
int GameLib_Init(int w,int h,char *title,int fps){
if(!Draw_Init(w,h,title,fps)){
return(0);
}
if(!Input_Init()){
return(0);
}
Audio_Init();
_game_size[0]=w;
_game_size[1]=h;
_game_pos[0]=0;
_game_pos[1]=0;
_ft=1000/fps;
return(1);
}
/////////////////////////////
// GameLib_AddEntity
//
// Adds an entity to the game.
void GameLib_AddEntity(Entity *e){
if(_n_entities>=_n_entities_res){
Entity **entity_aux;
int *entity_flag_aux;
int i;
// Grow the array
if(_n_entities_res==0)
_n_entities_res=32;
else
_n_entities_res*=2;
entity_aux=malloc(sizeof(Entity *)*_n_entities_res);
entity_flag_aux=malloc(sizeof(int)*_n_entities_res);
for(i=0;i<_n_entities;i++){
entity_aux[i]=_entity[i];
entity_flag_aux[i]=_entity_flag[i];
}
if(_entity){
free(_entity);
free(_entity_flag);
}
_entity=entity_aux;
_entity_flag=entity_flag_aux;
}
// Add the entity
_entity[_n_entities]=e;
_entity_flag[_n_entities]=1;
_n_entities++;
// Mark for light update
GameLib_EntityUpdateLight(e);
}
/////////////////////////////
// GameLib_UnrefEntity
//
// removes the reference to the entity.
int GameLib_UnrefEntity(Entity *e){
int i;
for(i=0;i<_n_entities;i++){
if(e==_entity[i]){
// Mark or unref
if(_entities_lock){
_entity_flag[i]=-2;
}else{
_entity[i]=NULL;
_entity_flag[i]=0;
}
_entities_compactate=1;
// Mark for light update
GameLib_EntityUpdateLight(e);
return(i);
}
}
return(-1);
}
/////////////////////////////
// GameLib_DelEntity
//
// Adds an entity to the game.
int GameLib_DelEntity(Entity *e){
int i;
if((i=GameLib_UnrefEntity(e))==-1){
return(0);
}
if(_entities_lock){
// Delete latter
_entity[i]=e;
_entity_flag[i]=-1;
}else{
// Delete now
Entity_Destroy(e);
}
return(1);
}
/////////////////////////////
// GameLib_Compactate
//
//
void GameLib_Compactate(){
int i,j;
j=0;
if(!_entities_compactate)
return;
for(i=0;i<_n_entities;i++){
if(!_entity[i] || _entity_flag[i]==-2)
continue;
if(_entity_flag[i]==-1){
Entity_Destroy(_entity[i]);
continue;
}
if(i>j){
_entity[j]=_entity[i];
_entity_flag[j]=_entity_flag[i];
}
j++;
}
_n_entities=j;
_entities_compactate=0;
_entities_lock=0;
}
/////////////////////////////
// GameLib_ProcLoop
//
// Process the loop.
int GameLib_ProcLoop(){
int i,j;
int repeat,count;
long long time;
// Process
time=Time_GetTime();
GameLib_Compactate();_entities_lock=1;
if(_gameproc){
_gameproc();
}
for(i=0;i<_n_entities;i++){
if(!_entity[i])
continue;
Entity_Process(_entity[i],_ft);
}
GameLib_Compactate();
t_proc+=Time_GetTime()-time;
// Colisions between entities
time=Time_GetTime();
GameLib_Compactate();_entities_lock=1;
count=0;
do{
repeat=0;
for(i=0;i<_n_entities;i++){
if(!(_entity[i]->flags&EntityFlag_Collision) || _entity[i]->mass<0.0f)
continue;
for(j=0;j<_n_entities;j++){
if(!(_entity[j]->flags&EntityFlag_Collision) || i==j)
continue;
if(Entity_Collide(_entity[i],_entity[j])){
repeat=1;
}
}
}
count++;
}while(repeat && count<10);
// Stop remaining collisions
if(count==10){
for(i=0;i<_n_entities;i++){
if(!(_entity[i]->flags&EntityFlag_Collision) || _entity[i]->mass<0.0f)
continue;
for(j=0;j<_n_entities;j++){
if(!(_entity[j]->flags&EntityFlag_Collision) || i==j)
continue;
if(Entity_Collide(_entity[i],_entity[j])){
vec2_set(_entity[i]->vel,0,0);
vec2_set(_entity[j]->vel,0,0);
}
}
}
}
GameLib_Compactate();
t_col+=Time_GetTime()-time;
// Process Overlaps
time=Time_GetTime();
GameLib_Compactate();_entities_lock=1;
for(i=0;i<_n_entities;i++){
if(!(_entity[i]->flags&EntityFlag_Overlap) || _entity[i]->mass<0.0f)
continue;
for(j=0;j<_n_entities;j++){
if(!(_entity[j]->flags&EntityFlag_Overlap) || i==j)
continue;
Entity_Overlaps(_entity[i],_entity[j]);
}
}
GameLib_Compactate();
t_over+=Time_GetTime()-time;
// Sort
int n,n2,swap;
n=_n_entities;
do{
n2=0;
for(i=1;i<n;i++){
swap=0;
if(_entity[i-1]->zorder > _entity[i]->zorder){
// Lower level
swap=1;
}else
if(_entity[i-1]->zorder < _entity[i]->zorder){
// Upper level
}else{
// Same level
if(_entity[i-1]->pos[1] > _entity[i]->pos[1]){
swap=1;
}
}
if(swap){
Entity *ent;
ent=_entity[i];
_entity[i]=_entity[i-1];
_entity[i-1]=ent;
n2=i;
}
}
n=n2;
}while(n>0);
// PostProcess
time=Time_GetTime();
GameLib_Compactate();_entities_lock=1;
for(i=0;i<_n_entities;i++){
Entity_PostProcess(_entity[i],_ft);
if(_entity[i]->flags&EntityFlag_UpdatedPos){
GameLib_EntityUpdateLight(_entity[i]);
}
}
if(_gamepostproc){
_gamepostproc();
}
GameLib_Compactate();
t_postproc+=Time_GetTime()-time;
fproc_count++;
return(_running);
}
/////////////////////////////
// GameLib_DrawLoop
//
//
void GameLib_DrawLoop(){
long long time;
int i;
time=Time_GetTime();
// Update Lights
//GameLib_UpdateIlumination();
// Limpiar pantalla
Draw_Clean(0,0,0);
// Draw entities
GameLib_Compactate();_entities_lock=1;
for(i=0;i<_n_entities;i++){
Entity *e;
// FIXME: This is a hack
e=_entity[i];
if(e->pos[0]<(_game_pos[0]-128))
continue;
if(e->pos[0]>(_game_pos[0]+_game_size[0]+128))
continue;
if(e->pos[1]<(_game_pos[1]-128))
continue;
if(e->pos[1]>(_game_pos[1]+_game_size[1]+128))
continue;
// Update ilumination of this entity
if(e->flags&EntityFlag_UpdateLight){
Entity_Iluminate(e,_entity,_n_entities);
e->flags&=~EntityFlag_UpdateLight;
}
Entity_Draw(e,-_game_pos[0],-_game_pos[1]);
}
if(_gamedraw){
_gamedraw();
}
GameLib_Compactate();
t_draw+=Time_GetTime()-time;
fdraw_count++;
}
/////////////////////////////
// GameLib_Loop
//
// Loops the game.
void GameLib_Loop(
void (*gameproc)(),
void (*gamepostproc)(),
void (*gamedraw)())
{
_running=1;
_gameproc=gameproc;
_gamepostproc=gamepostproc;
_gamedraw=gamedraw;
t_proc=0;
t_col=0;
t_over=0;
t_postproc=0;
t_draw=0;
fproc_count=0;
fdraw_count=0;
Draw_Loop(GameLib_ProcLoop,GameLib_DrawLoop);
if (gamelib_debug) {
printf("Profiling:::::::::\n");
printf("t_proc.....:%6lld\n",t_proc/fproc_count);
printf("t_col......:%6lld\n",t_col/fproc_count);
printf("t_over.....:%6lld\n",t_over/fproc_count);
printf("t_postproc.:%6lld\n",t_postproc/fproc_count);
printf("t_draw.....:%6lld\n",t_draw/fdraw_count);
}
}
/////////////////////////////
// GameLib_BreakLoop
//
// Breaks the game loop.
void GameLib_BreakLoop(){
_running=0;
}
/////////////////////////////
// GameLib_GetPos
// GameLib_SetPos
// GameLib_SetPos
//
//
void GameLib_GetPos(int pos[2]){
pos[0]=_game_pos[0];
pos[1]=_game_pos[1];
}
void GameLib_SetPos(int pos[2]){
_game_pos[0]=pos[0];
_game_pos[1]=pos[1];
}
void GameLib_GetSize(int size[2]){
size[0]=_game_size[0];
size[1]=_game_size[1];
}
/////////////////////////////
// GameLib_ForEachEn
//
// Deletes every entity.
void GameLib_DelEnts(){
int i;
for(i=0;i<_n_entities;i++){
if(!_entity[i])
continue;
Entity_Destroy(_entity[i]);
}
_n_entities=0;
}
/////////////////////////////
// GameLib_ForEachEn
//
// Iterates every entity.
void GameLib_ForEachEnt(int (*func)(Entity *ent)){
int i;
for(i=0;i<_n_entities;i++){
if(!_entity[i])
continue;
if(!func(_entity[i])){
break;
}
}
}
/////////////////////////////
// GameLib_PlaySound
//
//
void GameLib_PlaySound(AudioSnd snd,int x,int y){
float vleft,vright,dx,dy;
int r,cx,cy,off;
// Get the screen context
cx=_game_pos[0]+_game_size[0]/2;
cy=_game_pos[1]+_game_size[1]/2;
if(_game_size[0]>_game_size[1]){
r=_game_size[0]/2;
}else{
r=_game_size[1]/2;
}
r=r*1.2f;
off=r/10.0f;
// Calculate volumes
dx=x-(cx+off);
dy=y-(cy);
vright=1.0f-(sqrtf(dx*dx+dy*dy)/(float)r);
dx=x-(cx-off);
dy=y-(cy);
vleft=1.0f-(sqrtf(dx*dx+dy*dy)/(float)r);
// Clamp to 0
if(vleft<0.0f)
vleft=0.0f;
if(vright<0.0f)
vright=0.0f;
if(vleft<=0.0f && vright<=0.0f){
return;
}
// PLAY!
Audio_PlaySound(snd,vleft,vright);
}
/////////////////////////////
// GameLib_Iluminate
//
//
void GameLib_Iluminate(){
int i;
for(i=0;i<_n_entities;i++){
Entity_Iluminate(_entity[i],_entity,_n_entities);
}
}
/////////////////////////////
// GameLib_EntitySetLight
//
//
void GameLib_EntitySetLight(Entity *e,float r,float g,float b,float rad){
if(e->flags&EntityFlag_Light){
GameLib_EntityUpdateLight(e);
Entity_SetLight(e,r,g,b,rad);
GameLib_EntityUpdateLight(e);
}else{
Entity_SetLight(e,r,g,b,rad);
e->flags|=EntityFlag_UpdateLight;
}
}
/////////////////////////////
// GameLib_EntityUpdateLight
//
//
void GameLib_EntityUpdateLight(Entity *e){
if(e->flags&EntityFlag_Light){
int i;
vec2 max,min;
vec2_set(max,e->pos[0]+e->light[3],e->pos[1]+e->light[3]);
vec2_set(min,e->pos[0]-e->light[3],e->pos[1]-e->light[3]);
for(i=0;i<_n_entities;i++){
if( min[0]<=_entity[i]->pos[0] &&
max[0]>=_entity[i]->pos[0] &&
min[1]<=_entity[i]->pos[1] &&
max[1]>=_entity[i]->pos[1])
{
_entity[i]->flags|=EntityFlag_UpdateLight;
}
}
}else{
e->flags|=EntityFlag_UpdateLight;
}
}
/////////////////////////////
// GameLib_UpdateIlumination
//
//
void GameLib_UpdateIlumination(){
int i;
for(i=0;i<_n_entities;i++){
if(_entity[i]->flags&EntityFlag_UpdateLight){
Entity_Iluminate(_entity[i],_entity,_n_entities);
_entity[i]->flags&=~EntityFlag_UpdateLight;
}
}
}