Forum

Motorola Droid / Google Android: Quake

Discuss programming topics for the various GPL'd game engine sources.

Moderator: InsideQC Admins

Motorola Droid / Google Android: Quake

Postby Baker » Tue Jan 05, 2010 7:21 am

Update: http://code.google.com/p/glesquake/sour ... c/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!)

Image

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/contest ... ile-quake/
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby Baker » Tue Jan 05, 2010 8:42 am

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.
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby Baker » Tue Jan 05, 2010 10:50 am

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: Select all
/*
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);
   }
}
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am


Return to Engine Programming

Who is online

Users browsing this forum: No registered users and 1 guest