Pages: [1]
  Print  
Author Topic: Logging entity screen positions  (Read 20812 times)
MattPeterson
Nub


Cakes 0
Posts: 7


« on: May 29, 2008, 09:32:47 AM »

This is probably trivially easy for someone who is familiar with the ioQuake code, but for me it's trial-by-fire.

My lab group is considering using ioQuake for research purposes, and we need a way to log the screen positions of all of the visible entities.  The reason we need to do this is that we are studying eye movements during game play, and we need a way to save the regions of interest (i.e bounding boxes of entities, sorta) so that we can synchronize them with our eye tracking data.

I've been looking at the ioQuake source code, but I'm not sure at the best place to put in a hook to do this.  I stumbled across some source code for homing rockets, and although I'm not sure if it is the best place to start, it accomplishes some of what we need.

It:
(1) Scans through all of the entities
(2) Choses the entities that are within it's visibility cone
(3) Finds the center of mass of each entity

In addition, we need to:
(4) Project the center of mass onto the screen (or into the screens coordinate system).
(5) Log the center of mass, and [preferably] a bounding box that we can use for a region-of-interest on a frame-by-frame basis.

What I really need is persistent code that logs this data to disk through every cycle of the game.


Does anyone know a good place to start?  Any and all pointers will be appreciated!


thanks,
- Matt Peterson
http://archlab.gmu.edu/people/mpeters2/
Logged
Mr. Oho
Half-Nub


Cakes 0
Posts: 55

I will press the button!


« Reply #1 on: May 29, 2008, 11:32:37 AM »

Intersting Tongue

Sorry i possibly wont be of much help but heres some thoughts:

1)
Looping through entities is easy. They are simple arrays in both game and cgame (g_entities[MAX_GENTITIES]/cg_entities[MAX_GENTITIES]). End of G_RunFrame/CG_DrawActiveFrame would possibly be a good place to do this. But i think adding some logging code to trap_R_AddRefEntityToScene in cgame might also be worth some thoughts.

2)
This is where it gets a bit annoying i think. Even if you do it in the client (by looping through the entity array or by trap_R_AddRefEntityToScene) and theforce only get what the engine thinks the player sees youll still have lots of entitities that are in reality hidden behind walls and stuff (im not that experienced with ioQuake but i think they didnt change much). So youll have to run traces from player to entity but taking the model sizes into account including possible scaling and stuff. Theres a client trap named trap_R_ModelBounds but i never did much with it so dunno if it even does what i think.

3)
ent->r.currentOrigin/cent->lerpOrigin (sorry im not sure if these are the ideal variables... if not someone correct me plz) + trap_R_ModelBounds and some calculations? Sorry im bad at math :/

Good luck i hope it was atleast a bit helpful Tongue
Logged
MattPeterson
Nub


Cakes 0
Posts: 7


« Reply #2 on: May 29, 2008, 11:50:35 AM »

Ahh, good points.  For right now, we'd be happy to just be able to save the ROI (region-of-interest) for each entity, no matter what type of entity it is.  But eventually we it would be nice to log which entity and what type each entity is.

I had been thinking that to keep track of each individual entity, I should give each entity a unique identifier as soon as it is spawned.  For our purposes, I'd probably use the time when the entity is spawned as it's ID code.

Also, thanks for the tip on G_RunFrame/CG_DrawActiveFrame  -- I'll take a look at that to see if that would be a good place to loop through the entities. 

As for point #2, I didn't even think of that!  There ought to be a simple way to determine if an entity is truly visible or hidden behind a wall, but that's something I'll tackle later.


Thanks for the pointer.  I'll try inserting an entity loop into CG_DrawActiveFrame this afternoon and see what I get.

-Matt
Logged
Mr. Oho
Half-Nub


Cakes 0
Posts: 55

I will press the button!


« Reply #3 on: May 29, 2008, 12:03:34 PM »

Another quick thought since you seem to go for cgame: take a look a CG_ProcessEntity in cg_ent.c logging there might spare you finding out which entities are actualy valid.

Logged
MattPeterson
Nub


Cakes 0
Posts: 7


« Reply #4 on: June 04, 2008, 08:35:13 AM »

Here's a stupid question: who am I?  Or more specifically, what variable holds the current player's origin?
Logged
kick52
Member


Cakes -1
Posts: 229


« Reply #5 on: June 04, 2008, 03:15:19 PM »

Tongue
Sounds like some asshole coding a pathetic cheat.
Logged
Mr. Oho
Half-Nub


Cakes 0
Posts: 55

I will press the button!


« Reply #6 on: June 04, 2008, 03:56:34 PM »

Here's a stupid question: who am I?  Or more specifically, what variable holds the current player's origin?

You are cg_entities[cg.clientNum] so cg_entities[cg.clientNum].lerpOrigin might be a good place to look but im not sure this is the best.

Tongue
Sounds like some asshole coding a pathetic cheat.

I wouldnt be that sure Tongue Gamers eye movements seem to get alot of interest latley.
« Last Edit: June 04, 2008, 03:58:43 PM by Mr. Oho » Logged
MattPeterson
Nub


Cakes 0
Posts: 7


« Reply #7 on: June 05, 2008, 06:12:55 AM »

Thanks Mr. Oho.

   We had bad storms rip through the DC area yesterday, and before the power went out, I was looking at this variable:

cg.refdef.vieworg


  It's used by CG_TestModel_f() top draw an entity 100 units in front of the viewer.  Now that power is back on, I'm going to try my code later this morning -- hopefully it spits out something reasonable!

  Eventually I'm going to need to know where the projection plane (the screen) is relative to the viewpoint.  Does anybody know the distance, or what variable holds the distance of the screen from the viewpoint?


Tongue
Sounds like some asshole coding a pathetic cheat.

In case your are interested, our research, using movies of Quake (ugly frame-by-frame hand coding of regions-of-interest, but at least they were consistent from subject-to-subject), was presented last month at Vision Sciences.  Although our research isn't published yet, if you are interested I could send you a copy of our VSS poster.

http://archlab.gmu.edu/people/mpeters2/
« Last Edit: June 05, 2008, 06:24:57 AM by MattPeterson » Logged
Mr. Oho
Half-Nub


Cakes 0
Posts: 55

I will press the button!


« Reply #8 on: June 05, 2008, 08:27:34 AM »

cg.refdef.vieworg

Yeah that should be way better than the origin.

Eventually I'm going to need to know where the projection plane (the screen) is relative to the viewpoint.  Does anybody know the distance, or what variable holds the distance of the screen from the viewpoint?

Hmm 'projection plane'... i know the word but my crappy math strikes again ;/ You possibly already stumbled upon the viewaxis and fov_x/fov_y variables in refdef_t... not so sure this has anything to do with projection planes though hehe
Logged
MattPeterson
Nub


Cakes 0
Posts: 7


« Reply #9 on: June 06, 2008, 07:02:16 AM »

I've run into one little snag: I don't seem to be able to use (or easily forcce) stdio functions (e.g. fprintf) in cg_view.c. 

I tried trap_FS_FOpenFile(), etc., within CG_DrawActiveFrame(), but it doesn't seem to be working and no files were opened.

Code:
void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback )
{
...
fileHandle_t f;
char tempString[255];
...
// fp =fopen("EntityLocations.txt","a");
trap_FS_FOpenFile( "EntityLocations.txt", &f, FS_APPEND );
Com_sprintf (tempString, 255,  "cg.snap->numEntities = %d \n", cg.snap->numEntities);
// sprintf(tempString, "cg.snap->numEntities = %d \n", cg.snap->numEntities);
trap_FS_Write(tempString, strlen(tempString), f );
trap_FS_FCloseFile( f );
Logged
Mr. Oho
Half-Nub


Cakes 0
Posts: 55

I will press the button!


« Reply #10 on: June 06, 2008, 07:49:09 AM »

The engine wont let you access .txt files outside the pk3s but .dat or .cfg should work fine. If you want to use stdio functions you have to compile your libraries to native code and possibly start oa with +set vm_cgame 0 to allow the engine to use it. Though im not 100% sure about the last part as i never compiled native code for quake3 and its default in the game i mod for :/
« Last Edit: June 06, 2008, 07:59:12 AM by Mr. Oho » Logged
MattPeterson
Nub


Cakes 0
Posts: 7


« Reply #11 on: June 06, 2008, 03:00:20 PM »

Hmmmm....after trying several methods to log some of my results to the console using CG_Printf() and getting no results, I started to wonder whether my code was being called at all, so I tried something drastic and commented out CG_DrawActive() (I'm working in CG_DrawActiveFrame).

Code:
void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback )
{...
// actually issue the rendering calls
// CG_DrawActive( stereoView ); // msp - don't forget to uncomment this out

So, I recompiled and ran the game.  Sure enough, the graphics looked just fine, and from my understanding, commenting out CG_DrawActive() should have prevented the scenes from being drawn.

My next thought was that maybe the version of cg_view I was working on wasn't getting compiled.  So I typed some gobbledy-gook into CG_DrawActiveFrame() and tried to recompile.  Sure enough, gcc gave me a bunch of compile errors (I'm using OSX).  So it seems that my code is being compiled, but isn't being used.

Am I misunderstanding the flow of the program?  Isn't CG_DrawActiveFrame() called on every from to render the 3d view?
Logged
Mr. Oho
Half-Nub


Cakes 0
Posts: 55

I will press the button!


« Reply #12 on: June 06, 2008, 09:26:56 PM »

Hmm thats weird. Are you compiling .so (or whatever is the equivalent on mac) files? If so are you using the +set vm_cgame 0 command line switch? Maybe the engine is just using vms instead?
Logged
MattPeterson
Nub


Cakes 0
Posts: 7


« Reply #13 on: June 21, 2008, 09:16:03 AM »

Mr. Oho: thanks for all of your help.  It turns out that ioQuake wasn't running from the dlls.

So far, I've been able to successfully stream regions of interest (ROIs) to disk -- essentially the top-left and bottom-right coordinates of the bounding box as projected on the screen.  I've also been able to filter out the data based on whether on not an entity is visible or not (e.g. behind a wall).  I've accomplished this all within CG_DrawActiveFrame.


My next step is that I would like to be able to write to disk when an entity is spawned and when it dies.  Ideally, I'd like to be able to use the spawning function to give an entity a unique identifier, such as the system clock time, and use that to tag ROIs.

At this point, I'm having problems figuring out what function is called every time an entity is spawned.  I've put code snippets into CleintSpawn() and G_AddBot().  In my code, I've added some lines to respective functions that write "client spawned" or "Bot spawned" messages to disk.

Here is an example of the first two clines of my text file.  This is after I played a quick round of the single player game.


client spawned: 'noclass', serverTime =600, index = 1
client spawned: 'noclass', serverTime =650, index = 0

and here is the code that produces it:

Code:
void ClientSpawn(gentity_t *ent)
 {
...

// find a spawn point
// do it before setting health back up, so farthest
// ranging doesn't count this client
if ( client->sess.sessionTeam == TEAM_SPECTATOR )
{... }
else if (g_gametype.integer >= GT_CTF )
{... }
else
{...
}
//------
trap_FS_FOpenFile( "EntityLocations.dat", &f, FS_APPEND );
Q_snprintf(tempString, 512, "client spawned: '%s', serverTime =%d, index = %d\n",
ent->classname,
level.time, //client->pers.cmd.serverTime,
index
);
trap_FS_Write(tempString, strlen(tempString), f );
trap_FS_FCloseFile( f );


There are two interesting things to note: (1) I get two client messages right at the beginning, and (2) I get no bot messages.  In this game I made sure I killed two enemies before quiting. These messages seem to correspond to the enemy respawning:

client spawned: 'player', serverTime =66300, index = 1
client spawned: 'player', serverTime =89850, index = 1


Maybe part of the problem is that I'm misunderstanding the terminology.  I assumed that 'client' meant a person -- in single-player mode, that would be me.  Is a client also a bot? Is that why I get those later messages?  Also, G_AddBot() must not be getting called, because I'm not getting an messages in my text file with "bot" in them.


thanks,
Matt
Logged
Mr. Oho
Half-Nub


Cakes 0
Posts: 55

I will press the button!


« Reply #14 on: July 11, 2008, 04:05:23 PM »

Sorry for taking so long but i somehow got distracted by real life Tongue

Yeah you are right bots are clients too. They behave like normal clients besides having their input controled by the ai code (ent->r.svFlags&SVF_BOT is 1 if your client is a bot). I dont have source at hand right now to check but im pretty sure G_AddBot will be only used if you add a bot via the console.

Clients are a special case of entities as they are the only entities not allocated via G_Spawn. The first MAX_CLIENTS entities are reserved for clients and never used for anything else. You can assume enity index == client number.

For clients you could use player_die as a counter part to ClientSpawn i guess but for normal entities im not realy sure. You could put some code into G_Spawn/G_FreeEntity but the problem is you wont know anything about the entity when it is spawned besides its index so ud have to log types in G_FreeEntity. Not sure how practical that would be but maybe still better than adding logging code for every single entity spawning function in the code :/
Logged
Pages: [1]
  Print  
 
Jump to: