Inside3D!
     

Motorola Droid / Google Android: Quake

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Engine Programming
View previous topic :: View next topic  
Author Message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Jan 05, 2010 7:21 am    Post subject: Motorola Droid / Google Android: Quake Reply with quote

Update: http://code.google.com/p/glesquake/source/browse/#hg/quake/src/WinQuake (some developmental talk here; some discussion of the port is here)


vid: http://www.youtube.com/watch?v=-9Q3NK3iO7w

I've read the Droid platform runs OpenGL ES 1.0, largely similar to OpenGL 1.2. http://en.wikipedia.org/wiki/OpenGL_ES

Wikipedia:OpenGL ES wrote:
OpenGL ES 1.0 has been chosen as the official 3D graphics API in Symbian OS[2] and the Android platform[3]




Related: An attempted Quake2 port (in progress it appears) to Droid platform @ Sourceforge.

http://quake2-android.sourceforge.net/

Since Quake II is very similar to Quake 1, whatever changes in the source for the few OpenGL ES 1.0 differences and the system specific vidsetup/sound/controls could be derived. I say this because it looks like whatever Quake 1 port got expunged by id Software for trying to actually sell the game. (Sheesh!)



And I guess this page offers (offered? Is dated March 25) "bounties" to port Quake 1 to the Android (does that work? Dunno):

http://androidandme.com/2009/03/contests/android-bounty-ii-mobile-quake/
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Jan 05, 2010 8:42 am    Post subject: Reply with quote

Hah ... the developer behind the GLESQuake Droid port is Jack Palevich, the Direct3DQuake author.

I couldn't resist sending him an email thanking him for making the Droid port.

I also told him of MH's new Direct3D wrapper project page at http://www.quakeone.com/mh and invited him to stop by Inside3d and say hi to the remaining Quake 1 development community if interested.

/Too ironic.
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Jan 05, 2010 10:50 am    Post subject: Reply with quote

gl_rmain.cpp

About the only significantly changed source file I've found concerning rendering. [ A few network code changes. The GLESQuake doesn't support sound at this point so ...]

Well, other than the addition of a texture manager in gl_draw.c because it appears Android is a little memory impaired and the fact that GLQuake doesn't delete textures ...

I'm curious about the differences between OpenGL 1.1 +/- and OpenGL ES, hence my curiosity ...

Code:
/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// r_main.c

#include "quakedef.h"

entity_t   r_worldentity;

qboolean   r_cache_thrash;      // compatability

vec3_t      modelorg, r_entorigin;
entity_t   *currententity;

int         r_visframecount;   // bumped when going to a new PVS
int         r_framecount;      // used for dlight push checking

mplane_t   frustum[4];

int         c_brush_polys, c_alias_polys;

qboolean   envmap;            // true during envmap command capture

int         currenttexture = -1;      // to avoid unnecessary texture sets

int         cnttextures[2] = {-1, -1};     // cached

int         particletexture;   // little dot for particles
int         playertextures;      // up to 16 color translated skins

int         mirrortexturenum;   // quake texturenum, not gltexturenum
qboolean   mirror;
mplane_t   *mirror_plane;

//
// view origin
//
vec3_t   vup;
vec3_t   vpn;
vec3_t   vright;
vec3_t   r_origin;

float   r_world_matrix[16];
float   r_base_world_matrix[16];

//
// screen size info
//
refdef_t   r_refdef;

mleaf_t      *r_viewleaf, *r_oldviewleaf;

texture_t   *r_notexture_mip;

int      d_lightstylevalue[256];   // 8.8 fraction of base light value


void R_MarkLeaves (void);

cvar_t   r_norefresh = CVAR2("r_norefresh","0");
cvar_t   r_drawentities = CVAR2("r_drawentities","1");
cvar_t   r_drawviewmodel = CVAR2("r_drawviewmodel","1");
cvar_t   r_speeds = CVAR2("r_speeds","0");
cvar_t   r_fullbright = CVAR2("r_fullbright","0");
cvar_t   r_lightmap = CVAR2("r_lightmap","0");
cvar_t   r_shadows = CVAR2("r_shadows","0");
cvar_t   r_mirroralpha = CVAR2("r_mirroralpha","1");
cvar_t   r_wateralpha = CVAR2("r_wateralpha","1");
cvar_t   r_dynamic = CVAR2("r_dynamic","1");
cvar_t   r_novis = CVAR2("r_novis","0");

cvar_t   gl_finish = CVAR2("gl_finish","0");
cvar_t   gl_clear = CVAR2("gl_clear","0");
cvar_t   gl_cull = CVAR2("gl_cull","1");
cvar_t   gl_texsort = CVAR2("gl_texsort","1");
cvar_t   gl_smoothmodels = CVAR2("gl_smoothmodels","1");
cvar_t   gl_affinemodels = CVAR2("gl_affinemodels","1");
cvar_t   gl_polyblend = CVAR2("gl_polyblend","1");
cvar_t   gl_flashblend = CVAR2("gl_flashblend","1");
cvar_t   gl_playermip = CVAR2("gl_playermip","0");
cvar_t   gl_nocolors = CVAR2("gl_nocolors","0");
cvar_t   gl_keeptjunctions = CVAR2("gl_keeptjunctions","1");
cvar_t   gl_reporttjunctions = CVAR2("gl_reporttjunctions","0");
cvar_t   gl_doubleeyes = CVAR2("gl_doubleeys", "1");

extern   cvar_t   gl_ztrick;

/*
=================
R_CullBox

Returns true if the box is completely outside the frustom
=================
*/
qboolean R_CullBox (vec3_t mins, vec3_t maxs)
{
   int      i;

   for (i=0 ; i<4 ; i++)
      if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2)
         return true;
   return false;
}


void R_RotateForEntity (entity_t *e)
{
    glTranslatef (e->origin[0],  e->origin[1],  e->origin[2]);

    glRotatef (e->angles[1],  0, 0, 1);
    glRotatef (-e->angles[0],  0, 1, 0);
    glRotatef (e->angles[2],  1, 0, 0);
}

/*
=============================================================

  SPRITE MODELS

=============================================================
*/

/*
================
R_GetSpriteFrame
================
*/
mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
{
   msprite_t      *psprite;
   mspritegroup_t   *pspritegroup;
   mspriteframe_t   *pspriteframe;
   int            i, numframes, frame;
   float         *pintervals, fullinterval, targettime, time;

   psprite = (msprite_t*) currententity->model->cache.data;
   frame = currententity->frame;

   if ((frame >= psprite->numframes) || (frame < 0))
   {
      Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
      frame = 0;
   }

   if (psprite->frames[frame].type == SPR_SINGLE)
   {
      pspriteframe = psprite->frames[frame].frameptr;
   }
   else
   {
      pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
      pintervals = pspritegroup->intervals;
      numframes = pspritegroup->numframes;
      fullinterval = pintervals[numframes-1];

      time = cl.time + currententity->syncbase;

   // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
   // are positive, so we don't have to worry about division by 0
      targettime = time - ((int)(time / fullinterval)) * fullinterval;

      for (i=0 ; i<(numframes-1) ; i++)
      {
         if (pintervals[i] > targettime)
            break;
      }

      pspriteframe = pspritegroup->frames[i];
   }

   return pspriteframe;
}


/*
=================
R_DrawSpriteModel

=================
*/
void R_DrawSpriteModel (entity_t *e)
{
   vec3_t   point;
   mspriteframe_t   *frame;
   float      *up, *right;
   vec3_t      v_forward, v_right, v_up;
   msprite_t      *psprite;

   // don't even bother culling, because it's just a single
   // polygon without a surface cache
   frame = R_GetSpriteFrame (e);
   psprite = (msprite_t*) currententity->model->cache.data;

   if (psprite->type == SPR_ORIENTED)
   {   // bullet marks on walls
      AngleVectors (currententity->angles, v_forward, v_right, v_up);
      up = v_up;
      right = v_right;
   }
   else
   {   // normal sprite
      up = vup;
      right = vright;
   }

   glColor3f (1,1,1);

   GL_DisableMultitexture();

    GL_Bind(frame->gl_texturenum);

   glEnable (GL_ALPHA_TEST);

#ifdef USE_OPENGLES

   {
       float* pPoint = gVertexBuffer;
       float texCoords[] = {
         0, 1,
         0, 0,
         1, 0,
         1, 1
      };

      VectorMA (e->origin, frame->down, up, point);
      VectorMA (point, frame->left, right, pPoint);
      pPoint += 3;

      VectorMA (e->origin, frame->up, up, point);
      VectorMA (point, frame->left, right, pPoint);
      pPoint += 3;

      VectorMA (e->origin, frame->up, up, point);
      VectorMA (point, frame->right, right, pPoint);
      pPoint += 3;

      VectorMA (e->origin, frame->down, up, point);
      VectorMA (point, frame->right, right, pPoint);

      glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
      glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
      glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
   }

#else
   glBegin (GL_QUADS);

   glTexCoord2f (0, 1);
   VectorMA (e->origin, frame->down, up, point);
   VectorMA (point, frame->left, right, point);
   glVertex3fv (point);

   glTexCoord2f (0, 0);
   VectorMA (e->origin, frame->up, up, point);
   VectorMA (point, frame->left, right, point);
   glVertex3fv (point);

   glTexCoord2f (1, 0);
   VectorMA (e->origin, frame->up, up, point);
   VectorMA (point, frame->right, right, point);
   glVertex3fv (point);

   glTexCoord2f (1, 1);
   VectorMA (e->origin, frame->down, up, point);
   VectorMA (point, frame->right, right, point);
   glVertex3fv (point);

   glEnd ();
#endif

   glDisable (GL_ALPHA_TEST);
}

/*
=============================================================

  ALIAS MODELS

=============================================================
*/


#define NUMVERTEXNORMALS   162

float   r_avertexnormals[NUMVERTEXNORMALS][3] = {
#include "anorms.h"
};

vec3_t   shadevector;
float   shadelight, ambientlight;

// precalculated dot products for quantized angles
#define SHADEDOT_QUANT 16
float   r_avertexnormal_dots[SHADEDOT_QUANT][256] =
#include "anorm_dots.h"
;

float   *shadedots = r_avertexnormal_dots[0];

int   lastposenum;

/*
=============
GL_DrawAliasFrame
=============
*/
void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum)
{
   float   s, t;
   float    l;
   int      i, j;
   int      index;
   trivertx_t   *v, *verts;
   int      list;
   int      *order;
   vec3_t   point;
   float   *normal;
   int      count;

#ifdef USE_OPENGLES
   glEnableClientState(GL_COLOR_ARRAY);
#endif

lastposenum = posenum;

   verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
   verts += posenum * paliashdr->poseverts;
   order = (int *)((byte *)paliashdr + paliashdr->commands);

   while (1)
   {
      // get the vertex count and primitive type
      count = *order++;
      if (!count)
         break;      // done

#ifdef USE_OPENGLES
      {
         int primType;
         int c;
         float* pColor;
         float* pTexCoord;
         float* pPos;

         if (count < 0)
         {
            count = -count;
            primType = GL_TRIANGLE_FAN;
         }
         else
            primType = GL_TRIANGLE_STRIP;

         // texture coordinates come from the draw list
         glTexCoordPointer(2, GL_FLOAT, 0, gTexCoordBuffer);
         glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
         glColorPointer(4, GL_FLOAT, 0, gColorBuffer);

         pColor = gColorBuffer;
         pPos = gVertexBuffer;
         pTexCoord = gTexCoordBuffer;
         c = count;
         do
         {
            // texture coordinates come from the draw list
            *pTexCoord++ = ((float *)order)[0];
            *pTexCoord++ = ((float *)order)[1];
            order += 2;

            // normals and vertexes come from the frame list
            l = shadedots[verts->lightnormalindex] * shadelight;
            *pColor++ = l;
            *pColor++ = l;
            *pColor++ = l;
            *pColor++ = 1.0f;
            *pPos++ = verts->v[0];
            *pPos++ = verts->v[1];
            *pPos++ = verts->v[2];
            verts++;
          } while (--c);

         glDrawArrays(primType, 0, count);
      }

#else
      if (count < 0)
      {
         count = -count;
         glBegin (GL_TRIANGLE_FAN);
      }
      else
         glBegin (GL_TRIANGLE_STRIP);

      do
      {
         // texture coordinates come from the draw list
         glTexCoord2f (((float *)order)[0], ((float *)order)[1]);
         order += 2;

         // normals and vertexes come from the frame list
         l = shadedots[verts->lightnormalindex] * shadelight;
         glColor3f (l, l, l);
         glVertex3f (verts->v[0], verts->v[1], verts->v[2]);
         verts++;
      } while (--count);

      glEnd ();
#endif
   }

#ifdef USE_OPENGLES
   glDisableClientState(GL_COLOR_ARRAY);
#endif

}


/*
=============
GL_DrawAliasShadow
=============
*/
extern   vec3_t         lightspot;

void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum)
{
   float   s, t, l;
   int      i, j;
   int      index;
   trivertx_t   *v, *verts;
   int      list;
   int      *order;
   vec3_t   point;
   float   *normal;
   float   height, lheight;
   int      count;

   lheight = currententity->origin[2] - lightspot[2];

   height = 0;
   verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
   verts += posenum * paliashdr->poseverts;
   order = (int *)((byte *)paliashdr + paliashdr->commands);

   height = -lheight + 1.0;

   while (1)
   {
      // get the vertex count and primitive type
      count = *order++;
      if (!count)
         break;      // done

#ifdef USE_OPENGLES

      {
         int primType;
         int c;
         float* pVertex;

         if (count < 0)
         {
            count = -count;
            primType = GL_TRIANGLE_FAN;
         }
         else
            primType = GL_TRIANGLE_STRIP;

         pVertex = gVertexBuffer;
         for(c = 0; c < count; c++)
         {
            // texture coordinates come from the draw list
            // (skipped for shadows) glTexCoord2fv ((float *)order);
            order += 2;

            // normals and vertexes come from the frame list
            pVertex[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
            pVertex[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
            pVertex[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];

            pVertex[0] -= shadevector[0]*(pVertex[2]+lheight);
            pVertex[1] -= shadevector[1]*(pVertex[2]+lheight);
            pVertex[2] = height;
   //         height -= 0.001;

            pVertex += 3;
            verts++;
         }

         glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
         glDrawArrays(primType, 0, count);
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      }

#else

      if (count < 0)
      {
         count = -count;
         glBegin (GL_TRIANGLE_FAN);
      }
      else
         glBegin (GL_TRIANGLE_STRIP);

      do
      {
         // texture coordinates come from the draw list
         // (skipped for shadows) glTexCoord2fv ((float *)order);
         order += 2;

         // normals and vertexes come from the frame list
         point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
         point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
         point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];

         point[0] -= shadevector[0]*(point[2]+lheight);
         point[1] -= shadevector[1]*(point[2]+lheight);
         point[2] = height;
//         height -= 0.001;
         glVertex3fv (point);

         verts++;
      } while (--count);

      glEnd ();

#endif

   }
}



/*
=================
R_SetupAliasFrame

=================
*/
void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr)
{
   int            pose, numposes;
   float         interval;

   if ((frame >= paliashdr->numframes) || (frame < 0))
   {
      Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
      frame = 0;
   }

   pose = paliashdr->frames[frame].firstpose;
   numposes = paliashdr->frames[frame].numposes;

   if (numposes > 1)
   {
      interval = paliashdr->frames[frame].interval;
      pose += (int)(cl.time / interval) % numposes;
   }

   GL_DrawAliasFrame (paliashdr, pose);
}



/*
=================
R_DrawAliasModel

=================
*/
void R_DrawAliasModel (entity_t *e)
{
   int         i, j;
   int         lnum;
   vec3_t      dist;
   float      add;
   model_t      *clmodel;
   vec3_t      mins, maxs;
   aliashdr_t   *paliashdr;
   trivertx_t   *verts, *v;
   int         index;
   float      s, t, an;
   int         anim;

   clmodel = currententity->model;

   VectorAdd (currententity->origin, clmodel->mins, mins);
   VectorAdd (currententity->origin, clmodel->maxs, maxs);

   if (R_CullBox (mins, maxs))
      return;


   VectorCopy (currententity->origin, r_entorigin);
   VectorSubtract (r_origin, r_entorigin, modelorg);

   //
   // get lighting information
   //

   ambientlight = shadelight = R_LightPoint (currententity->origin);

   // allways give the gun some light
   if (e == &cl.viewent && ambientlight < 24)
      ambientlight = shadelight = 24;

   for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
   {
      if (cl_dlights[lnum].die >= cl.time)
      {
         VectorSubtract (currententity->origin,
                     cl_dlights[lnum].origin,
                     dist);
         add = cl_dlights[lnum].radius - Length(dist);

         if (add > 0) {
            ambientlight += add;
            //ZOID models should be affected by dlights as well
            shadelight += add;
         }
      }
   }

   // clamp lighting so it doesn't overbright as much
   if (ambientlight > 128)
      ambientlight = 128;
   if (ambientlight + shadelight > 192)
      shadelight = 192 - ambientlight;

   // ZOID: never allow players to go totally black
   i = currententity - cl_entities;
   if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
      if (ambientlight < 8)
         ambientlight = shadelight = 8;

   // HACK HACK HACK -- no fullbright colors, so make torches full light
   if (!strcmp (clmodel->name, "progs/flame2.mdl")
      || !strcmp (clmodel->name, "progs/flame.mdl") )
      ambientlight = shadelight = 256;

   shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
   shadelight = shadelight / 200.0;

   an = e->angles[1]/180*M_PI;
   shadevector[0] = cos(-an);
   shadevector[1] = sin(-an);
   shadevector[2] = 1;
   VectorNormalize (shadevector);

   //
   // locate the proper data
   //
   paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);

   c_alias_polys += paliashdr->numtris;

   //
   // draw all the triangles
   //

   GL_DisableMultitexture();

    glPushMatrix ();
   R_RotateForEntity (e);

   if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) {
      glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8));
// double size of eyes, since they are really hard to see in gl
      glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2);
   } else {
      glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
      glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
   }

   anim = (int)(cl.time*10) & 3;
    GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]);

   // we can't dynamically colormap textures, so they are cached
   // seperately for the players.  Heads are just uncolored.
   if (currententity->colormap != vid.colormap && !gl_nocolors.value)
   {
      i = currententity - cl_entities;
      if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
          GL_Bind(playertextures - 1 + i);
   }

   if (gl_smoothmodels.value)
      glShadeModel (GL_SMOOTH);
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

   if (gl_affinemodels.value)
      glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);

   R_SetupAliasFrame (currententity->frame, paliashdr);

   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

   glShadeModel (GL_FLAT);
   if (gl_affinemodels.value)
      glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

   glPopMatrix ();

   if (r_shadows.value)
   {
      glPushMatrix ();
      R_RotateForEntity (e);
      glDisable (GL_TEXTURE_2D);
      glEnable (GL_BLEND);
      glColor4f (0,0,0,0.5);
      GL_DrawAliasShadow (paliashdr, lastposenum);
      glEnable (GL_TEXTURE_2D);
      glDisable (GL_BLEND);
      glColor4f (1,1,1,1);
      glPopMatrix ();
   }

}

//==================================================================================

/*
=============
R_DrawEntitiesOnList
=============
*/
void R_DrawEntitiesOnList (void)
{
   int      i;

   if (!r_drawentities.value)
      return;

   // draw sprites seperately, because of alpha blending
   for (i=0 ; i<cl_numvisedicts ; i++)
   {
      currententity = cl_visedicts[i];

      switch (currententity->model->type)
      {
      case mod_alias:
         R_DrawAliasModel (currententity);
         break;

      case mod_brush:
         R_DrawBrushModel (currententity);
         break;

      default:
         break;
      }
   }

   for (i=0 ; i<cl_numvisedicts ; i++)
   {
      currententity = cl_visedicts[i];

      switch (currententity->model->type)
      {
      case mod_sprite:
         R_DrawSpriteModel (currententity);
         break;

      default :
         break;
      }
   }
}

/*
=============
R_DrawViewModel
=============
*/
void R_DrawViewModel (void)
{
   float      ambient[4], diffuse[4];
   int         j;
   int         lnum;
   vec3_t      dist;
   float      add;
   dlight_t   *dl;
   int         ambientlight, shadelight;

   if (!r_drawviewmodel.value)
      return;

   if (chase_active.value)
      return;

   if (envmap)
      return;

   if (!r_drawentities.value)
      return;

   if (cl.items & IT_INVISIBILITY)
      return;

   if (cl.stats[STAT_HEALTH] <= 0)
      return;

   currententity = &cl.viewent;
   if (!currententity->model)
      return;

   j = R_LightPoint (currententity->origin);

   if (j < 24)
      j = 24;      // allways give some light on gun
   ambientlight = j;
   shadelight = j;

// add dynamic lights
   for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
   {
      dl = &cl_dlights[lnum];
      if (!dl->radius)
         continue;
      if (!dl->radius)
         continue;
      if (dl->die < cl.time)
         continue;

      VectorSubtract (currententity->origin, dl->origin, dist);
      add = dl->radius - Length(dist);
      if (add > 0)
         ambientlight += (int) add;
   }

   ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128;
   diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128;

   // hack the depth range to prevent view model from poking into walls
#ifdef USE_OPENGLES
   glDepthRangef(gldepthmin, gldepthmin + 0.3f*(gldepthmax-gldepthmin));
   R_DrawAliasModel (currententity);
   glDepthRangef(gldepthmin, gldepthmax);
#else
   glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
   R_DrawAliasModel (currententity);
   glDepthRange (gldepthmin, gldepthmax);
#endif
}


/*
============
R_PolyBlend
============
*/
void R_PolyBlend (void)
{
   if (!gl_polyblend.value)
      return;
   if (!v_blend[3])
      return;

   GL_DisableMultitexture();

   glDisable (GL_ALPHA_TEST);
   glEnable (GL_BLEND);
   glDisable (GL_DEPTH_TEST);
   glDisable (GL_TEXTURE_2D);

    glLoadIdentity ();

    glRotatef (-90,  1, 0, 0);       // put Z going up
    glRotatef (90,  0, 0, 1);       // put Z going up

   glColor4fv (v_blend);

#ifdef USE_OPENGLES
   float vertex[3*4] = {
      10, 100, 100,
      10, -100, 100,
      10, -100, -100,
      10, 100, -100
   };
   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   glVertexPointer( 3, GL_FLOAT, 0, vertex);
   glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
#else
   glBegin (GL_QUADS);

   glVertex3f (10, 100, 100);
   glVertex3f (10, -100, 100);
   glVertex3f (10, -100, -100);
   glVertex3f (10, 100, -100);
   glEnd ();
#endif

   glDisable (GL_BLEND);
   glEnable (GL_TEXTURE_2D);
   glEnable (GL_ALPHA_TEST);
}


int SignbitsForPlane (mplane_t *out)
{
   int   bits, j;

   // for fast box on planeside test

   bits = 0;
   for (j=0 ; j<3 ; j++)
   {
      if (out->normal[j] < 0)
         bits |= 1<<j;
   }
   return bits;
}


void R_SetFrustum (void)
{
   int      i;

   if (r_refdef.fov_x == 90)
   {
      // front side is visible

      VectorAdd (vpn, vright, frustum[0].normal);
      VectorSubtract (vpn, vright, frustum[1].normal);

      VectorAdd (vpn, vup, frustum[2].normal);
      VectorSubtract (vpn, vup, frustum[3].normal);
   }
   else
   {
      // rotate VPN right by FOV_X/2 degrees
      RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
      // rotate VPN left by FOV_X/2 degrees
      RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
      // rotate VPN up by FOV_X/2 degrees
      RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
      // rotate VPN down by FOV_X/2 degrees
      RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
   }

   for (i=0 ; i<4 ; i++)
   {
      frustum[i].type = PLANE_ANYZ;
      frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
      frustum[i].signbits = SignbitsForPlane (&frustum[i]);
   }
}



/*
===============
R_SetupFrame
===============
*/
void R_SetupFrame (void)
{
   int            edgecount;
   vrect_t         vrect;
   float         w, h;

// don't allow cheats in multiplayer
   if (cl.maxclients > 1)
      Cvar_Set ("r_fullbright", "0");

   R_AnimateLight ();

   r_framecount++;

// build the transformation matrix for the given view angles
   VectorCopy (r_refdef.vieworg, r_origin);

   AngleVectors (r_refdef.viewangles, vpn, vright, vup);

// current viewleaf
   r_oldviewleaf = r_viewleaf;
   r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);

   V_SetContentsColor (r_viewleaf->contents);
   V_CalcBlend ();

   r_cache_thrash = false;

   c_brush_polys = 0;
   c_alias_polys = 0;

}

#ifdef USE_OPENGLES

void MYgluPerspective( float fovy, float aspect,
           float zNear, float zFar )
{
   float xmin, xmax, ymin, ymax;

   ymax = zNear * tan( fovy * M_PI / 360.0f );
   ymin = -ymax;

   xmin = ymin * aspect;
   xmax = ymax * aspect;

   glFrustumf( xmin, xmax, ymin, ymax, zNear, zFar );
}

#else

void MYgluPerspective( GLdouble fovy, GLdouble aspect,
           GLdouble zNear, GLdouble zFar )
{
   GLdouble xmin, xmax, ymin, ymax;

   ymax = zNear * tan( fovy * M_PI / 360.0 );
   ymin = -ymax;

   xmin = ymin * aspect;
   xmax = ymax * aspect;

   glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
}
#endif

#define DO_OWN_MATRIX_MATH
#ifdef DO_OWN_MATRIX_MATH
// We can't count on being able to read back the model view matrix, so calculate it ourselves.

#define I(_i, _j) ((_j)+ 4*(_i))

void mulMM(float* r, const float* lhs, const float* rhs)
{
    float const* const m = lhs;
    for (int i=0 ; i<4 ; i++) {
        register const float rhs_i0 = rhs[ I(i,0) ];
        register float ri0 = m[ I(0,0) ] * rhs_i0;
        register float ri1 = m[ I(0,1) ] * rhs_i0;
        register float ri2 = m[ I(0,2) ] * rhs_i0;
        register float ri3 = m[ I(0,3) ] * rhs_i0;
        for (int j=1 ; j<4 ; j++) {
            register const float rhs_ij = rhs[ I(i,j) ];
            ri0 += m[ I(j,0) ] * rhs_ij;
            ri1 += m[ I(j,1) ] * rhs_ij;
            ri2 += m[ I(j,2) ] * rhs_ij;
            ri3 += m[ I(j,3) ] * rhs_ij;
        }
        r[ I(i,0) ] = ri0;
        r[ I(i,1) ] = ri1;
        r[ I(i,2) ] = ri2;
        r[ I(i,3) ] = ri3;
    }
}

static void setIdentityM(float* sm, int smOffset) {
    for (int i=0 ; i<16 ; i++) {
        sm[smOffset + i] = 0;
    }
    for(int i = 0; i < 16; i += 5) {
        sm[smOffset + i] = 1.0f;
    }
}

static void translateM(float* m, int mOffset,
        float x, float y, float z) {
    for (int i=0 ; i<4 ; i++) {
        int mi = mOffset + i;
        m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z;
    }
}

static float length(float x, float y, float z) {
   return (float) sqrtf(x * x + y * y + z * z);
}

static void setRotateM(float* rm, int rmOffset,
            float a, float x, float y, float z)
{
    rm[rmOffset + 3] = 0;
    rm[rmOffset + 7] = 0;
    rm[rmOffset + 11]= 0;
    rm[rmOffset + 12]= 0;
    rm[rmOffset + 13]= 0;
    rm[rmOffset + 14]= 0;
    rm[rmOffset + 15]= 1;
    a *= (float) (M_PI / 180.0f);
    float s = (float) sinf(a);
    float c = (float) cosf(a);
    if (1.0f == x && 0.0f == y && 0.0f == z) {
        rm[rmOffset + 5] = c;   rm[rmOffset + 10]= c;
        rm[rmOffset + 6] = s;   rm[rmOffset + 9] = -s;
        rm[rmOffset + 1] = 0;   rm[rmOffset + 2] = 0;
        rm[rmOffset + 4] = 0;   rm[rmOffset + 8] = 0;
        rm[rmOffset + 0] = 1;
    } else if (0.0f == x && 1.0f == y && 0.0f == z) {
        rm[rmOffset + 0] = c;   rm[rmOffset + 10]= c;
        rm[rmOffset + 8] = s;   rm[rmOffset + 2] = -s;
        rm[rmOffset + 1] = 0;   rm[rmOffset + 4] = 0;
        rm[rmOffset + 6] = 0;   rm[rmOffset + 9] = 0;
        rm[rmOffset + 5] = 1;
    } else if (0.0f == x && 0.0f == y && 1.0f == z) {
        rm[rmOffset + 0] = c;   rm[rmOffset + 5] = c;
        rm[rmOffset + 1] = s;   rm[rmOffset + 4] = -s;
        rm[rmOffset + 2] = 0;   rm[rmOffset + 6] = 0;
        rm[rmOffset + 8] = 0;   rm[rmOffset + 9] = 0;
        rm[rmOffset + 10]= 1;
    } else {
        float len = length(x, y, z);
        if (1.0f != len) {
            float recipLen = 1.0f / len;
            x *= recipLen;
            y *= recipLen;
            z *= recipLen;
        }
        float nc = 1.0f - c;
        float xy = x * y;
        float yz = y * z;
        float zx = z * x;
        float xs = x * s;
        float ys = y * s;
        float zs = z * s;
        rm[rmOffset +  0] = x*x*nc +  c;
        rm[rmOffset +  4] =  xy*nc - zs;
        rm[rmOffset +  8] =  zx*nc + ys;
        rm[rmOffset +  1] =  xy*nc + zs;
        rm[rmOffset +  5] = y*y*nc +  c;
        rm[rmOffset +  9] =  yz*nc - xs;
        rm[rmOffset +  2] =  zx*nc - ys;
        rm[rmOffset +  6] =  yz*nc + xs;
        rm[rmOffset + 10] = z*z*nc +  c;
    }
}

static void rotateM(float* m,
            float a, float x, float y, float z) {
    float temp[16];
    float temp2[16];
    setRotateM(temp, 0, a, x, y, z);
    mulMM(temp2, m, temp);
    memcpy(m, temp2, 16 * sizeof(float));
}

#undef I

#endif // DO_OWN_MATRIX_MATH

/*
=============
R_SetupGL
=============
*/
void R_SetupGL (void)
{
   float   screenaspect;
   float   yfov;
   int      i;
   extern   int glwidth, glheight;
   int      x, x2, y2, y, w, h;

   //
   // set up viewpoint
   //
   glMatrixMode(GL_PROJECTION);
    glLoadIdentity ();
   x = r_refdef.vrect.x * glwidth/vid.width;
   x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width;
   y = (vid.height-r_refdef.vrect.y) * glheight/vid.height;
   y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height;

   // fudge around because of frac screen scale
   if (x > 0)
      x--;
   if (x2 < glwidth)
      x2++;
   if (y2 < 0)
      y2--;
   if (y < glheight)
      y++;

   w = x2 - x;
   h = y - y2;

   if (envmap)
   {
      x = y2 = 0;
      w = h = 256;
   }

   glViewport (glx + x, gly + y2, w, h);
    screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height;
//   yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI;
    MYgluPerspective (r_refdef.fov_y,  screenaspect,  4,  4096);

   if (mirror)
   {
      if (mirror_plane->normal[2])
         glScalef (1, -1, 1);
      else
         glScalef (-1, 1, 1);
      glCullFace(GL_BACK);
   }
   else
      glCullFace(GL_FRONT);

   glMatrixMode(GL_MODELVIEW);

#ifdef DO_OWN_MATRIX_MATH

   float mv[16];
    setIdentityM(mv, 0);

    rotateM(mv, -90,  1, 0, 0);       // put Z going up
    rotateM(mv, 90,  0, 0, 1);       // put Z going up
    rotateM(mv, -r_refdef.viewangles[2],  1, 0, 0);
    rotateM(mv, -r_refdef.viewangles[0],  0, 1, 0);
    rotateM(mv, -r_refdef.viewangles[1],  0, 0, 1);
    translateM(mv, 0, -r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);

    glLoadMatrixf(mv);

    memcpy(r_world_matrix, mv, sizeof(r_world_matrix));

#else
    glLoadIdentity ();

    glRotatef (-90,  1, 0, 0);       // put Z going up
    glRotatef (90,  0, 0, 1);       // put Z going up
    glRotatef (-r_refdef.viewangles[2],  1, 0, 0);
    glRotatef (-r_refdef.viewangles[0],  0, 1, 0);
    glRotatef (-r_refdef.viewangles[1],  0, 0, 1);
    glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);

#ifdef USE_OPENGLES

    static qboolean initialized;
    static qboolean haveGL_OES_matrix_get;
    static qboolean haveGL_OES_query_matrix;

#if 0
    if (! initialized) {
        const char* extensions = (const char*) glGetString(GL_EXTENSIONS);
        haveGL_OES_matrix_get =
            strstr(extensions, "GL_OES_matrix_get") != NULL;
        haveGL_OES_query_matrix =
            strstr(extensions, "GL_OES_query_matrix") != NULL;
        initialized = true;
    }
    if (haveGL_OES_query_matrix) {
        GLfixed mantissa[16];
        GLint exponent[16];
        glQueryMatrixxOES( mantissa, exponent );
        for(int i = 0; i < 16; i++) {
            r_world_matrix[i] = scalbnf(mantissa[i], exponent[i]-16);
        }
    }
    else if (haveGL_OES_matrix_get) {
        glGetIntegerv (MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES,
                (GLint*) r_world_matrix);
    }
    else
#endif
       {
        // No way to get the world matix, set to identity
        memset(r_world_matrix, 0, sizeof(r_world_matrix));
        for(i = 0; i < 16; i += 5) {
            r_world_matrix[i] = 1.0f;
        }
    }
#else
   glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);
#endif
#endif // DO_OWN_MATRIX_MATH
   //
   // set drawing parms
   //
   if (gl_cull.value)
      glEnable(GL_CULL_FACE);
   else
      glDisable(GL_CULL_FACE);

   glDisable(GL_BLEND);
   glDisable(GL_ALPHA_TEST);
   glEnable(GL_DEPTH_TEST);
}

/*
================
R_RenderScene

r_refdef must be set before the first call
================
*/
void R_RenderScene (void)
{
   R_SetupFrame ();

   R_SetFrustum ();

   R_SetupGL ();

   R_MarkLeaves ();   // done here so we know if we're in water

   R_DrawWorld ();      // adds static entities to the list

   S_ExtraUpdate ();   // don't let sound get messed up if going slow

   R_DrawEntitiesOnList ();

   GL_DisableMultitexture();

   R_RenderDlights ();

   R_DrawParticles ();

#ifdef GLTEST
   Test_Draw ();
#endif

}


/*
=============
R_Clear
=============
*/
void R_Clear (void)
{
   if (r_mirroralpha.value != 1.0)
   {
      if (gl_clear.value)
         glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      else
         glClear (GL_DEPTH_BUFFER_BIT);
      gldepthmin = 0;
      gldepthmax = 0.5;
      glDepthFunc (GL_LEQUAL);
   }
   else if (gl_ztrick.value)
   {
      static int trickframe;

      if (gl_clear.value)
         glClear (GL_COLOR_BUFFER_BIT);

      trickframe++;
      if (trickframe & 1)
      {
         gldepthmin = 0;
         gldepthmax = 0.49999;
         glDepthFunc (GL_LEQUAL);
      }
      else
      {
         gldepthmin = 1;
         gldepthmax = 0.5;
         glDepthFunc (GL_GEQUAL);
      }
   }
   else
   {
      if (gl_clear.value)
         glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      else
         glClear (GL_DEPTH_BUFFER_BIT);
      gldepthmin = 0;
      gldepthmax = 1;
      glDepthFunc (GL_LEQUAL);
   }

#ifdef USE_OPENGLES
   glDepthRangef (gldepthmin, gldepthmax);
#else
   glDepthRange (gldepthmin, gldepthmax);
#endif
}

/*
=============
R_Mirror
=============
*/
void R_Mirror (void)
{
   float      d;
   msurface_t   *s;
   entity_t   *ent;

   if (!mirror)
      return;

   memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix));

   d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist;
   VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg);

   d = DotProduct (vpn, mirror_plane->normal);
   VectorMA (vpn, -2*d, mirror_plane->normal, vpn);

   r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180;
   r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180;
   r_refdef.viewangles[2] = -r_refdef.viewangles[2];

   ent = &cl_entities[cl.viewentity];
   if (cl_numvisedicts < MAX_VISEDICTS)
   {
      cl_visedicts[cl_numvisedicts] = ent;
      cl_numvisedicts++;
   }

   gldepthmin = 0.5;
   gldepthmax = 1;
#ifdef USE_OPENGLES
   glDepthRangef (gldepthmin, gldepthmax);
#else
   glDepthRange (gldepthmin, gldepthmax);
#endif
   glDepthFunc (GL_LEQUAL);

   R_RenderScene ();
   R_DrawWaterSurfaces ();

   gldepthmin = 0;
   gldepthmax = 0.5;
#ifdef USE_OPENGLES
   glDepthRangef (gldepthmin, gldepthmax);
#else
   glDepthRange (gldepthmin, gldepthmax);
#endif
   glDepthFunc (GL_LEQUAL);

   // blend on top
   glEnable (GL_BLEND);
   glMatrixMode(GL_PROJECTION);
   if (mirror_plane->normal[2])
      glScalef (1,-1,1);
   else
      glScalef (-1,1,1);
   glCullFace(GL_FRONT);
   glMatrixMode(GL_MODELVIEW);

   glLoadMatrixf (r_base_world_matrix);

   glColor4f (1,1,1,r_mirroralpha.value);
   s = cl.worldmodel->textures[mirrortexturenum]->texturechain;
   for ( ; s ; s=s->texturechain)
      R_RenderBrushPoly (s);
   cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL;
   glDisable (GL_BLEND);
   glColor4f (1,1,1,1);
}

/*
================
R_RenderView

r_refdef must be set before the first call
================
*/
void R_RenderView (void)
{
   double time1 = 0.0;
   double time2;
   GLfloat colors[4] = {(GLfloat) 0.0, (GLfloat) 0.0, (GLfloat) 1, (GLfloat) 0.20};

   if (r_norefresh.value)
      return;

   if (!r_worldentity.model || !cl.worldmodel)
      Sys_Error ("R_RenderView: NULL worldmodel");

   if (r_speeds.value)
   {
      glFinish ();
      time1 = Sys_FloatTime ();
      c_brush_polys = 0;
      c_alias_polys = 0;
   }

   mirror = false;

   if (gl_finish.value)
      glFinish ();

   R_Clear ();

   // render normal view

/***** Experimental silly looking fog ******
****** Use r_fullbright if you enable ******
   glFogi(GL_FOG_MODE, GL_LINEAR);
   glFogfv(GL_FOG_COLOR, colors);
   glFogf(GL_FOG_END, 512.0);
   glEnable(GL_FOG);
********************************************/

   R_RenderScene ();
   R_DrawViewModel ();
   R_DrawWaterSurfaces ();

//  More fog right here :)
//   glDisable(GL_FOG);
//  End of all fog code...

   // render mirror view
   R_Mirror ();

   R_PolyBlend ();

   if (r_speeds.value)
   {
//      glFinish ();
      time2 = Sys_FloatTime ();
      Con_Printf ("%3i ms  %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys);
   }
}
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Engine Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group