Index | FAQ | Search | Memberlist | Usergroups | Profile | Log in to check your private messages | Log in | Register

Motorola Droid / Google Android: Quake

| Inside3d Forums Forum Index -> Engine Programming

View previous topic :: View next topic
Author | Message
--- | ---
Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Tue Jan 05, 2010 7:21 am Post subject: Motorola Droid / Google Android: Quake |

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 |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Tue Jan 05, 2010 8:42 am Post subject: |

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 |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Tue Jan 05, 2010 10:50 am Post subject: |

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 |

Display posts from previous:

| 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