Move the surface chain links out of the surfaces.

The links are now in "instance surfaces". For non-instanced models (world,
doors, plats etc (ie, world and its sub-models)), there will be one
instance surface per model surface. However, for instanced models (ammo
boxes etc), there will be many, dynamically allocated (not yet
implemented). This commit gets the static instance surfaces working.
This commit is contained in:
Bill Currie 2011-12-17 19:14:14 +09:00
parent 497e4b7dfd
commit 87b78e5533
7 changed files with 196 additions and 90 deletions

View file

@ -38,6 +38,6 @@ extern qboolean skyloaded;
extern vec5_t skyvec[6][4]; extern vec5_t skyvec[6][4];
void R_DrawSky (void); void R_DrawSky (void);
void R_DrawSkyChain (const msurface_t *s); void R_DrawSkyChain (const instsurf_t *s);
#endif // __QF_GL_sky_h #endif // __QF_GL_sky_h

View file

@ -68,13 +68,33 @@ typedef struct {
vec3_t position; vec3_t position;
} mvertex_t; } mvertex_t;
/** Instanced surface data.
There will be one of these for each surface in the world model. This
covers the sub-models in the world model. These instanced surfaces will
be allocated in one block at map load time and then never freed until
the next map load.
However, for instanced brush models (ammo boxes, health boxes, etc), an
instanced surface will be allocated for each surface for each model
once per frame. These instanced surfaces will be mass-freed each frame.
*/
typedef struct instsurf_s {
struct instsurf_s *next; ///< next in free/alloc list
struct instsurf_s *tex_chain; ///< next in texture chain
struct instsurf_s *lm_chain; ///< next in lightmap chain
struct msurface_s *surface; ///< surface to render
vec_t *transform;
float *color;
} instsurf_t;
typedef struct texture_s { typedef struct texture_s {
char name[16]; char name[16];
unsigned int width, height; unsigned int width, height;
int gl_texturenum; int gl_texturenum;
int gl_fb_texturenum; int gl_fb_texturenum;
struct msurface_s *texturechain; // for gl_texsort drawing instsurf_t *tex_chain; // for gl_texsort drawing
struct msurface_s **texturechain_tail; instsurf_t **tex_chain_tail;
int anim_total; // total tenths in sequence ( 0 = no) int anim_total; // total tenths in sequence ( 0 = no)
int anim_min, anim_max; // time for this frame min <=time< max int anim_min, anim_max; // time for this frame min <=time< max
struct texture_s *anim_next; // in the animation sequence struct texture_s *anim_next; // in the animation sequence
@ -136,8 +156,7 @@ typedef struct msurface_s {
int light_s, light_t; // gl lightmap coordinates int light_s, light_t; // gl lightmap coordinates
glpoly_t *polys; // multiple if warped glpoly_t *polys; // multiple if warped
struct msurface_s *texturechain; instsurf_t *instsurf; ///< null if not part of world model/sub-model
// struct msurface_s *lightmapchain; // Quake 2 ???
mtexinfo_t *texinfo; mtexinfo_t *texinfo;

View file

@ -178,6 +178,9 @@ void D_DrawSurfaces (void);
void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist); void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist);
void R_StepActiveU (edge_t *pedge); void R_StepActiveU (edge_t *pedge);
void R_RemoveEdges (edge_t *pedge); void R_RemoveEdges (edge_t *pedge);
void R_AddTexture (texture_t *tex);
void R_ClearTextures (void);
void R_InitSurfaceChains (model_t *model);
extern void R_Surf8Start (void); extern void R_Surf8Start (void);
extern void R_Surf8End (void); extern void R_Surf8End (void);
@ -191,8 +194,6 @@ extern int r_polycount;
extern int r_wholepolycount; extern int r_wholepolycount;
extern model_t *cl_worldmodel; extern model_t *cl_worldmodel;
extern texture_t **r_texture_chains;
extern int r_num_texture_chains;
extern int *pfrustum_indexes[4]; extern int *pfrustum_indexes[4];

View file

@ -545,7 +545,7 @@ static void
R_Mirror (void) R_Mirror (void)
{ {
float d; float d;
msurface_t *s; // msurface_t *s;
// if (!mirror) // FIXME: Broken // if (!mirror) // FIXME: Broken
return; return;
@ -590,6 +590,7 @@ R_Mirror (void)
color_white[3] = r_mirroralpha->value * 255; color_white[3] = r_mirroralpha->value * 255;
qfglColor4ubv (color_white); qfglColor4ubv (color_white);
#if 0//FIXME
s = r_worldentity.model->textures[mirrortexturenum]->texturechain; s = r_worldentity.model->textures[mirrortexturenum]->texturechain;
for (; s; s = s->texturechain) { for (; s; s = s->texturechain) {
texture_t *tex; texture_t *tex;
@ -611,6 +612,7 @@ R_Mirror (void)
// R_RenderBrushPoly (s, tex); // FIXME: Need to move R_Mirror to gl_rsurf.c, and uncommment this line! // R_RenderBrushPoly (s, tex); // FIXME: Need to move R_Mirror to gl_rsurf.c, and uncommment this line!
} }
r_worldentity.model->textures[mirrortexturenum]->texturechain = NULL; r_worldentity.model->textures[mirrortexturenum]->texturechain = NULL;
#endif
qfglColor3ubv (color_white); qfglColor3ubv (color_white);
} }

View file

@ -66,32 +66,6 @@ static __attribute__ ((used)) const char rcsid[] =
int r_init = 0; int r_init = 0;
texture_t **r_texture_chains;
int r_num_texture_chains;
static int max_texture_chains;
static void
R_AddTexture (texture_t *tex)
{
int i;
if (r_num_texture_chains == max_texture_chains) {
max_texture_chains += 64;
r_texture_chains = realloc (r_texture_chains,
max_texture_chains * sizeof (texture_t *));
for (i = r_num_texture_chains; i < max_texture_chains; i++)
r_texture_chains[i] = 0;
}
r_texture_chains[r_num_texture_chains++] = tex;
tex->texturechain = NULL;
tex->texturechain_tail = &tex->texturechain;
}
static void
R_ClearTextures (void)
{
r_num_texture_chains = 0;
}
/* /*
R_Envmap_f R_Envmap_f
@ -196,8 +170,6 @@ register_textures (model_t *model)
tex = model->textures[i]; tex = model->textures[i];
if (!tex) if (!tex)
continue; continue;
if (tex->texturechain_tail)
continue;
R_AddTexture (tex); R_AddTexture (tex);
} }
} }
@ -240,16 +212,18 @@ R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
if (!strncmp (tex->name, "window02_1", 10)) if (!strncmp (tex->name, "window02_1", 10))
mirrortexturenum = i; mirrortexturenum = i;
} }
R_InitSurfaceChains (r_worldentity.model);
R_AddTexture (r_notexture_mip);
register_textures (r_worldentity.model); register_textures (r_worldentity.model);
for (i = 0; i < num_models; i++) { for (i = 0; i < num_models; i++) {
if (!models[i]) if (!models[i])
continue; continue;
if (*models[i]->name == '*')
continue;
if (models[i] != r_worldentity.model && models[i]->type == mod_brush) if (models[i] != r_worldentity.model && models[i]->type == mod_brush)
register_textures (models[i]); register_textures (models[i]);
} }
tex = r_notexture_mip;
tex->texturechain = NULL;
tex->texturechain_tail = &tex->texturechain;
} }
void void

View file

@ -62,22 +62,26 @@ int skytexturenum;
glpoly_t *fullbright_polys[MAX_GLTEXTURES]; glpoly_t *fullbright_polys[MAX_GLTEXTURES];
msurface_t *waterchain = NULL; instsurf_t *waterchain = NULL;
msurface_t **waterchain_tail = &waterchain; instsurf_t **waterchain_tail = &waterchain;
msurface_t *sky_chain; instsurf_t *sky_chain;
msurface_t **sky_chain_tail; instsurf_t **sky_chain_tail;
#define CHAIN_SURF_F2B(surf,chain) \ #define CHAIN_SURF_F2B(surf,chain) \
do { \ do { \
*(chain##_tail) = (surf); \ instsurf_t *inst = (surf)->instsurf; \
(chain##_tail) = &(surf)->texturechain; \ inst->surface = (surf); \
*(chain##_tail) = inst; \
(chain##_tail) = &inst->tex_chain; \
*(chain##_tail) = 0; \ *(chain##_tail) = 0; \
} while (0) } while (0)
#define CHAIN_SURF_B2F(surf,chain) \ #define CHAIN_SURF_B2F(surf,chain) \
do { \ do { \
(surf)->texturechain = (chain); \ instsurf_t *inst = (surf)->instsurf; \
(chain) = (surf); \ inst->surface = (surf); \
inst->tex_chain = (chain); \
(chain) = inst; \
} while (0) } while (0)
extern int lightmap_textures; extern int lightmap_textures;
@ -85,6 +89,46 @@ extern qboolean lightmap_modified[MAX_LIGHTMAPS];
extern glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; extern glpoly_t *lightmap_polys[MAX_LIGHTMAPS];
extern glRect_t lightmap_rectchange[MAX_LIGHTMAPS]; extern glRect_t lightmap_rectchange[MAX_LIGHTMAPS];
static texture_t **r_texture_chains;
static int r_num_texture_chains;
static int max_texture_chains;
static instsurf_t *static_chains;
void
R_AddTexture (texture_t *tex)
{
int i;
if (r_num_texture_chains == max_texture_chains) {
max_texture_chains += 64;
r_texture_chains = realloc (r_texture_chains,
max_texture_chains * sizeof (texture_t *));
for (i = r_num_texture_chains; i < max_texture_chains; i++)
r_texture_chains[i] = 0;
}
r_texture_chains[r_num_texture_chains++] = tex;
tex->tex_chain = NULL;
tex->tex_chain_tail = &tex->tex_chain;
}
void
R_InitSurfaceChains (model_t *model)
{
int i;
if (static_chains)
free (static_chains);
static_chains = calloc (model->nummodelsurfaces, sizeof (instsurf_t));
for (i = 0; i < model->nummodelsurfaces; i++)
model->surfaces[i].instsurf = static_chains + i;
}
void
R_ClearTextures (void)
{
r_num_texture_chains = 0;
}
/* /*
R_TextureAnimation R_TextureAnimation
@ -247,7 +291,8 @@ void
R_DrawWaterSurfaces (void) R_DrawWaterSurfaces (void)
{ {
int i; int i;
msurface_t *s; instsurf_t *s;
msurface_t *fa;
if (!waterchain) if (!waterchain)
return; return;
@ -262,13 +307,19 @@ R_DrawWaterSurfaces (void)
} }
i = -1; i = -1;
for (s = waterchain; s; s = s->texturechain) { for (s = waterchain; s; s = s->tex_chain) {
if (i != s->texinfo->texture->gl_texturenum) { fa = s->surface;
i = s->texinfo->texture->gl_texturenum; if (s->transform)
qfglLoadMatrixf (s->transform);
else
qfglLoadMatrixf (r_world_matrix);
if (i != fa->texinfo->texture->gl_texturenum) {
i = fa->texinfo->texture->gl_texturenum;
qfglBindTexture (GL_TEXTURE_2D, i); qfglBindTexture (GL_TEXTURE_2D, i);
} }
EmitWaterPolys (s); EmitWaterPolys (fa);
} }
qfglLoadMatrixf (r_world_matrix);
waterchain = NULL; waterchain = NULL;
waterchain_tail = &waterchain; waterchain_tail = &waterchain;
@ -283,7 +334,8 @@ static inline void
DrawTextureChains (int disable_blend, int do_bind) DrawTextureChains (int disable_blend, int do_bind)
{ {
int i; int i;
msurface_t *s; instsurf_t *s;
msurface_t *fa;
texture_t *tex; texture_t *tex;
if (gl_mtex_active_tmus >= 2) { if (gl_mtex_active_tmus >= 2) {
@ -307,11 +359,22 @@ DrawTextureChains (int disable_blend, int do_bind)
qfglBindTexture (GL_TEXTURE_2D, tex->gl_fb_texturenum); qfglBindTexture (GL_TEXTURE_2D, tex->gl_fb_texturenum);
qglActiveTexture (gl_mtex_enum + 1); qglActiveTexture (gl_mtex_enum + 1);
for (s = tex->texturechain; s; s = s->texturechain) { for (s = tex->tex_chain; s; s = s->tex_chain) {
fa = s->surface;
if (s->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (s->transform);
}
if (s->color && do_bind)
qfglColor4fv (s->color);
qfglBindTexture (GL_TEXTURE_2D, lightmap_textures + qfglBindTexture (GL_TEXTURE_2D, lightmap_textures +
s->lightmaptexturenum); fa->lightmaptexturenum);
if (s->transform)
qfglPopMatrix ();
if (s->color && do_bind)
qfglColor3ubv (color_white);
R_RenderBrushPoly_3 (s); R_RenderBrushPoly_3 (fa);
} }
qglActiveTexture (gl_mtex_enum + 2); qglActiveTexture (gl_mtex_enum + 2);
@ -320,11 +383,23 @@ DrawTextureChains (int disable_blend, int do_bind)
qglActiveTexture (gl_mtex_enum + 0); qglActiveTexture (gl_mtex_enum + 0);
} else { } else {
qglActiveTexture (gl_mtex_enum + 1); qglActiveTexture (gl_mtex_enum + 1);
for (s = tex->texturechain; s; s = s->texturechain) { for (s = tex->tex_chain; s; s = s->tex_chain) {
fa = s->surface;
qfglBindTexture (GL_TEXTURE_2D, lightmap_textures + qfglBindTexture (GL_TEXTURE_2D, lightmap_textures +
s->lightmaptexturenum); fa->lightmaptexturenum);
R_RenderBrushPoly_2 (s); if (s->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (s->transform);
}
if (s->color && do_bind)
qfglColor4fv (s->color);
R_RenderBrushPoly_2 (fa);
if (s->transform)
qfglPopMatrix ();
if (s->color && do_bind)
qfglColor3ubv (color_white);
} }
qglActiveTexture (gl_mtex_enum + 0); qglActiveTexture (gl_mtex_enum + 0);
@ -347,8 +422,18 @@ DrawTextureChains (int disable_blend, int do_bind)
if (do_bind) if (do_bind)
qfglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); qfglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum);
for (s = tex->texturechain; s; s = s->texturechain) for (s = tex->tex_chain; s; s = s->tex_chain) {
R_RenderBrushPoly_1 (s); if (s->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (s->transform);
}
R_RenderBrushPoly_1 (s->surface);
if (s->transform)
qfglPopMatrix ();
if (s->color && do_bind)
qfglColor3ubv (color_white);
}
} }
if (disable_blend) if (disable_blend)
qfglEnable (GL_BLEND); qfglEnable (GL_BLEND);
@ -365,12 +450,12 @@ clear_texture_chains (void)
tex = r_texture_chains[i]; tex = r_texture_chains[i];
if (!tex) if (!tex)
continue; continue;
tex->texturechain = NULL; tex->tex_chain = NULL;
tex->texturechain_tail = &tex->texturechain; tex->tex_chain_tail = &tex->tex_chain;
} }
tex = r_notexture_mip; tex = r_notexture_mip;
tex->texturechain = NULL; tex->tex_chain = NULL;
tex->texturechain_tail = &tex->texturechain; tex->tex_chain_tail = &tex->tex_chain;
} }
static inline void static inline void
@ -395,7 +480,7 @@ chain_surface (msurface_t *surf)
fullbright_polys[tex->gl_fb_texturenum]; fullbright_polys[tex->gl_fb_texturenum];
fullbright_polys[tex->gl_fb_texturenum] = surf->polys; fullbright_polys[tex->gl_fb_texturenum] = surf->polys;
} }
CHAIN_SURF_F2B (surf, tex->texturechain); CHAIN_SURF_F2B (surf, tex->tex_chain);
} }
} }

View file

@ -639,14 +639,16 @@ R_DrawSkyBoxPoly (const glpoly_t *poly)
} }
static void static void
EmitSkyPolys (float speedscale, const msurface_t *fa) EmitSkyPolys (float speedscale, const instsurf_t *sc)
{ {
float length, s, t; float length, s, t;
float *v; float *v;
int i; int i;
glpoly_t *p; glpoly_t *p;
vec3_t dir; vec3_t dir;
msurface_t *fa = sc->surface;
//FIXME transform/color
for (p = fa->polys; p; p = p->next) { for (p = fa->polys; p; p = p->next) {
qfglBegin (GL_POLYGON); qfglBegin (GL_POLYGON);
for (i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE) { for (i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE) {
@ -682,21 +684,27 @@ draw_poly (const glpoly_t *poly)
} }
static void static void
draw_black_sky_polys (const msurface_t *sky_chain) draw_black_sky_polys (const instsurf_t *sky_chain)
{ {
const msurface_t *sc = sky_chain; const instsurf_t *sc = sky_chain;
qfglDisable (GL_BLEND); qfglDisable (GL_BLEND);
qfglDisable (GL_TEXTURE_2D); qfglDisable (GL_TEXTURE_2D);
qfglColor3ubv (color_black); qfglColor3ubv (color_black);
while (sc) { while (sc) {
glpoly_t *p = sc->polys; glpoly_t *p = sc->surface->polys;
if (sc->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (sc->transform);
}
while (p) { while (p) {
draw_poly (p); draw_poly (p);
p = p->next; p = p->next;
} }
sc = sc->texturechain; if (sc->transform)
qfglPushMatrix ();
sc = sc->tex_chain;
} }
qfglEnable (GL_TEXTURE_2D); qfglEnable (GL_TEXTURE_2D);
qfglEnable (GL_BLEND); qfglEnable (GL_BLEND);
@ -704,36 +712,37 @@ draw_black_sky_polys (const msurface_t *sky_chain)
} }
static void static void
draw_skybox_sky_polys (const msurface_t *sky_chain) draw_skybox_sky_polys (const instsurf_t *sky_chain)
{ {
const msurface_t *sc = sky_chain; const instsurf_t *sc = sky_chain;
qfglDepthMask (GL_FALSE); qfglDepthMask (GL_FALSE);
qfglDisable (GL_DEPTH_TEST); qfglDisable (GL_DEPTH_TEST);
while (sc) { while (sc) {
glpoly_t *p = sc->polys; glpoly_t *p = sc->surface->polys;
//FIXME transform/color
while (p) { while (p) {
R_DrawSkyBoxPoly (p); R_DrawSkyBoxPoly (p);
p = p->next; p = p->next;
} }
sc = sc->texturechain; sc = sc->tex_chain;
} }
qfglEnable (GL_DEPTH_TEST); qfglEnable (GL_DEPTH_TEST);
qfglDepthMask (GL_TRUE); qfglDepthMask (GL_TRUE);
} }
static void static void
draw_skydome_sky_polys (const msurface_t *sky_chain) draw_skydome_sky_polys (const instsurf_t *sky_chain)
{ {
// this function is not yet implemented so just draw black // this function is not yet implemented so just draw black
draw_black_sky_polys (sky_chain); draw_black_sky_polys (sky_chain);
} }
static void static void
draw_id_sky_polys (const msurface_t *sky_chain) draw_id_sky_polys (const instsurf_t *sky_chain)
{ {
const msurface_t *sc = sky_chain; const instsurf_t *sc = sky_chain;
float speedscale; float speedscale;
speedscale = r_realtime / 16; speedscale = r_realtime / 16;
@ -742,7 +751,7 @@ draw_id_sky_polys (const msurface_t *sky_chain)
qfglBindTexture (GL_TEXTURE_2D, solidskytexture); qfglBindTexture (GL_TEXTURE_2D, solidskytexture);
while (sc) { while (sc) {
EmitSkyPolys (speedscale, sc); EmitSkyPolys (speedscale, sc);
sc = sc->texturechain; sc = sc->tex_chain;
} }
if (gl_sky_multipass->int_val) { if (gl_sky_multipass->int_val) {
@ -754,28 +763,34 @@ draw_id_sky_polys (const msurface_t *sky_chain)
qfglBindTexture (GL_TEXTURE_2D, alphaskytexture); qfglBindTexture (GL_TEXTURE_2D, alphaskytexture);
while (sc) { while (sc) {
EmitSkyPolys (speedscale, sc); EmitSkyPolys (speedscale, sc);
sc = sc->texturechain; sc = sc->tex_chain;
} }
} }
} }
static void static void
draw_z_sky_polys (const msurface_t *sky_chain) draw_z_sky_polys (const instsurf_t *sky_chain)
{ {
const msurface_t *sc = sky_chain; const instsurf_t *sc = sky_chain;
qfglColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); qfglColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
qfglDisable (GL_BLEND); qfglDisable (GL_BLEND);
qfglDisable (GL_TEXTURE_2D); qfglDisable (GL_TEXTURE_2D);
qfglColor3ubv (color_black); qfglColor3ubv (color_black);
while (sc) { while (sc) {
glpoly_t *p = sc->polys; glpoly_t *p = sc->surface->polys;
if (sc->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (sc->transform);
}
while (p) { while (p) {
draw_poly (p); draw_poly (p);
p = p->next; p = p->next;
} }
sc = sc->texturechain; if (sc->transform)
qfglPopMatrix ();
sc = sc->tex_chain;
} }
qfglColor3ubv (color_white); qfglColor3ubv (color_white);
qfglEnable (GL_TEXTURE_2D); qfglEnable (GL_TEXTURE_2D);
@ -784,7 +799,7 @@ draw_z_sky_polys (const msurface_t *sky_chain)
} }
void void
R_DrawSkyChain (const msurface_t *sky_chain) R_DrawSkyChain (const instsurf_t *sky_chain)
{ {
if (gl_sky_clip->int_val > 2) { if (gl_sky_clip->int_val > 2) {
draw_black_sky_polys (sky_chain); draw_black_sky_polys (sky_chain);
@ -807,15 +822,19 @@ R_DrawSkyChain (const msurface_t *sky_chain)
} }
if (gl_sky_debug->int_val) { if (gl_sky_debug->int_val) {
const msurface_t *sc; const instsurf_t *sc;
qfglDisable (GL_TEXTURE_2D); qfglDisable (GL_TEXTURE_2D);
if (gl_sky_debug->int_val & 1) { if (gl_sky_debug->int_val & 1) {
sc = sky_chain; sc = sky_chain;
qfglColor3ub (255, 255, 255); qfglColor3ub (255, 255, 255);
while (sc) { while (sc) {
glpoly_t *p = sc->polys; glpoly_t *p = sc->surface->polys;
if (sc->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (sc->transform);
}
while (p) { while (p) {
int i; int i;
@ -826,7 +845,7 @@ R_DrawSkyChain (const msurface_t *sky_chain)
qfglEnd (); qfglEnd ();
p = p->next; p = p->next;
} }
sc = sc->texturechain; sc = sc->tex_chain;
} }
} }
if (gl_sky_debug->int_val & 2) { if (gl_sky_debug->int_val & 2) {
@ -834,8 +853,12 @@ R_DrawSkyChain (const msurface_t *sky_chain)
qfglColor3ub (0, 255, 0); qfglColor3ub (0, 255, 0);
qfglBegin (GL_POINTS); qfglBegin (GL_POINTS);
while (sc) { while (sc) {
glpoly_t *p = sc->polys; glpoly_t *p = sc->surface->polys;
if (sc->transform) {
qfglPushMatrix ();
qfglLoadMatrixf (sc->transform);
}
while (p) { while (p) {
int i; int i;
vec3_t x, c = { 0, 0, 0 }; vec3_t x, c = { 0, 0, 0 };
@ -849,7 +872,9 @@ R_DrawSkyChain (const msurface_t *sky_chain)
qfglVertex3fv (c); qfglVertex3fv (c);
p = p->next; p = p->next;
} }
sc = sc->texturechain; if (sc->transform)
qfglPopMatrix ();
sc = sc->tex_chain;
} }
qfglEnd (); qfglEnd ();
} }