/* * R_EnableColorShell */ void R_EnableShell(boolean_t enable) { if (enable == r_state.shell_enabled) return; r_state.shell_enabled = enable; if (enable) { glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0, 0.0); R_EnableBlend(true); R_BlendFunc(GL_SRC_ALPHA, GL_ONE); if (r_state.lighting_enabled) R_ProgramParameter1f("OFFSET", r_view.time / 3.0); } else { R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_EnableBlend(false); glPolygonOffset(0.0, 0.0); glDisable(GL_POLYGON_OFFSET_FILL); if (r_state.lighting_enabled) R_ProgramParameter1f("OFFSET", 0.0); } }
/** * @sa R_DrawParticles */ static void R_SetBlendMode (int mode) { switch (mode) { case BLEND_REPLACE: R_TexEnv(GL_REPLACE); break; case BLEND_ONE: R_BlendFunc(GL_SRC_ALPHA, GL_ONE); break; case BLEND_BLEND: R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; case BLEND_ADD: R_BlendFunc(GL_ONE, GL_ONE); break; case BLEND_FILTER: R_BlendFunc(GL_ZERO, GL_SRC_COLOR); break; case BLEND_INVFILTER: R_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); break; default: Com_Error(ERR_DROP, "unknown blend mode"); break; } }
/* * @brief */ void R_DrawCoronas(void) { if (!r_coronas->value) return; if (!r_view.num_coronas) return; R_EnableTexture(&texunit_diffuse, false); R_EnableColorArray(true); R_ResetArrayState(); R_BlendFunc(GL_SRC_ALPHA, GL_ONE); for (uint16_t i = 0; i < r_view.num_coronas; i++) { const r_corona_t *c = &r_view.coronas[i]; const vec_t f = c->radius * c->flicker * sin(0.09 * r_view.time); // use at least 12 verts, more for larger coronas const uint16_t num_verts = Clamp(c->radius / 8.0, 12, 64); memcpy(&r_state.color_array[0], c->color, sizeof(vec3_t)); r_state.color_array[3] = r_coronas->value; // set origin color // and the corner colors memset(&r_state.color_array[4], 0, num_verts * 2 * sizeof(vec4_t)); memcpy(&r_state.vertex_array_3d[0], c->origin, sizeof(vec3_t)); uint32_t vert_index = 3; // and the origin for (uint16_t j = 0; j <= num_verts; j++) { // now draw the corners const vec_t a = j / (vec_t) num_verts * M_PI * 2; vec3_t v; VectorCopy(c->origin, v); VectorMA(v, cos(a) * (c->radius + f), r_view.right, v); VectorMA(v, sin(a) * (c->radius + f), r_view.up, v); memcpy(&r_state.vertex_array_3d[vert_index], v, sizeof(vec3_t)); vert_index += 3; } glDrawArrays(GL_TRIANGLE_FAN, 0, vert_index / 3); } R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_EnableColorArray(false); R_EnableTexture(&texunit_diffuse, true); R_Color(NULL); }
/** * @brief Manages all state for the specified surface and stage. * @sa R_DrawMaterialSurfaces */ static void R_SetSurfaceStageState (const mBspSurface_t *surf, const materialStage_t *stage) { /* bind the texture */ R_BindTexture(stage->image->texnum); /* and optionally the lightmap */ R_StageLighting(surf, stage); R_StageGlow(stage); /* load the texture matrix for rotations, stretches, etc.. */ R_StageTextureMatrix(surf, stage); /* set the blend function, ensuring a good default */ if (stage->flags & STAGE_BLEND) R_BlendFunc(stage->blend.src, stage->blend.dest); else R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /* for terrain, enable the color array */ if (stage->flags & (STAGE_TAPE | STAGE_TERRAIN | STAGE_DIRTMAP)) R_EnableColorArray(true); else R_EnableColorArray(false); /* when not using the color array, resolve the shade color */ if (!r_state.color_array_enabled) { vec4_t color; if (stage->flags & STAGE_COLOR) /* explicit */ VectorCopy(stage->color, color); else if (stage->flags & STAGE_ENVMAP) /* implied */ VectorCopy(surf->lightColor, color); /** @todo WTF? surely it was supposed to use the specular color */ else /* default */ VectorSet(color, 1.0, 1.0, 1.0); /* modulate the alpha value for pulses */ if (stage->flags & STAGE_PULSE) { /* disable fog, since it also sets alpha */ R_EnableFog(false); color[3] = stage->pulse.dhz; } else { /* ensure fog is available */ R_EnableFog(true); color[3] = 1.0; } R_Color(color); } }
/* * @brief Draws all particles for the current frame. */ void R_DrawParticles(const r_element_t *e, const size_t count) { size_t i, j; R_EnableColorArray(true); R_ResetArrayState(); // alter the array pointers R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, r_particle_state.verts); R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, r_particle_state.texcoords); R_BindArray(GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, r_particle_state.colors); const GLuint base = (uintptr_t) e->data; for (i = j = 0; i < count; i++, e++) { const r_particle_t *p = (const r_particle_t *) e->element; // bind the particle's texture if (p->image->texnum != texunit_diffuse.texnum) { if (i > j) { // draw pending particles glDrawArrays(GL_QUADS, (base + j) * 4, (i - j) * 4); j = i; } R_BindTexture(p->image->texnum); R_BlendFunc(GL_SRC_ALPHA, p->blend); } } if (i > j) { // draw any remaining particles glDrawArrays(GL_QUADS, (base + j) * 4, (i - j) * 4); } // restore array pointers R_BindDefaultArray(GL_VERTEX_ARRAY); R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY); R_BindDefaultArray(GL_COLOR_ARRAY); R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_EnableColorArray(false); R_Color(NULL); }
/* * R_SetDEfaultState * * Sets OpenGL state parameters to appropiate defaults. */ void R_SetDefaultState(void) { int i; r_texunit_t *tex; // setup vertex array pointers glEnableClientState(GL_VERTEX_ARRAY); R_BindDefaultArray(GL_VERTEX_ARRAY); R_EnableColorArray(true); R_BindDefaultArray(GL_COLOR_ARRAY); R_EnableColorArray(false); glEnableClientState(GL_NORMAL_ARRAY); R_BindDefaultArray(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); // setup texture units for (i = 0; i < r_config.max_texunits && i < MAX_GL_TEXUNITS; i++) { tex = &r_state.texunits[i]; tex->texture = GL_TEXTURE0_ARB + i; R_EnableTexture(tex, true); R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY); if (i > 0) // turn them off for now R_EnableTexture(tex, false); } R_SelectTexture(&texunit_diffuse); // alpha test parameters glAlphaFunc(GL_GREATER, 0.25); // stencil test parameters glStencilFunc(GL_GEQUAL, 1, 0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // fog parameters glFogi(GL_FOG_MODE, GL_LINEAR); glFogf(GL_FOG_DENSITY, 0.0); glFogf(GL_FOG_START, FOG_START); glFogf(GL_FOG_END, FOG_END); // alpha blend parameters R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); }
/** * @note No need to reset the blend mode - R_Setup2D will do this * @sa R_Setup2D */ void R_DrawParticles (void) { ptl_t *p; int i; if (!r_particles->integer) return; for (i = 0, p = r_particleArray; i < r_numParticles; i++, p++) if (p->inuse && !p->invis) { /* test for visibility */ if (p->levelFlags && !((1 << refdef.worldlevel) & p->levelFlags)) continue; if (p->program != NULL) R_UseProgram(p->program); /* set blend mode and draw gfx */ R_SetBlendMode(p->blend); switch (p->style) { case STYLE_LINE: R_DrawPtlLine(p); break; case STYLE_CIRCLE: R_DrawPtlCircle(p); break; default: break; } if (p->pic) R_DrawSprite(p); if (p->model) R_DrawParticleModel(p); R_TexEnv(GL_MODULATE); R_UseProgram(NULL); } R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_Color(NULL); }
void R_DrawCoronas (void) { int i, j, k; vec3_t v; if (!r_coronas->integer) return; if (!refdef.numCoronas) return; R_EnableTexture(&texunit_diffuse, false); R_EnableColorArray(true); R_ResetArrayState(); R_BlendFunc(GL_ONE, GL_ONE); for (k = 0; k < refdef.numCoronas; k++) { const corona_t *c = &refdef.coronas[k]; int verts, vertind; if (!c->radius) continue; /* use at least 12 verts, more for larger coronas */ verts = 12 + c->radius / 8; memcpy(&r_state.color_array[0], c->color, sizeof(vec3_t)); r_state.color_array[3] = 1.0f; /* set origin color */ /* and the corner colors */ memset(&r_state.color_array[4], 0, verts * 2 * sizeof(vec4_t)); memcpy(&r_state.vertex_array_3d[0], c->org, sizeof(vec3_t)); vertind = 3; /* and the origin */ for (i = verts; i >= 0; i--) { /* now draw the corners */ const float a = (M_PI * 2 / verts) * i; for (j = 0; j < 3; j++) v[j] = c->org[j] + r_locals.right[j] * (float) cos(a) * c->radius + r_locals.up[j] * (float) sin(a) * c->radius; memcpy(&r_state.vertex_array_3d[vertind], v, sizeof(vec3_t)); vertind += 3; } glDrawArrays(GL_TRIANGLE_FAN, 0, vertind / 3); refdef.batchCount++; } R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_EnableColorArray(false); R_EnableTexture(&texunit_diffuse, true); R_Color(nullptr); }
/** * @brief Iterates the specified surfaces list, updating materials as they are * encountered, and rendering all visible stages. State is lazily managed * throughout the iteration, so there is a concerted effort to restore the * state after all surface stages have been rendered. */ void R_DrawMaterialSurfaces (const mBspSurfaces_t *surfs, GLushort *indexPtr) { int i; if (!r_materials->integer || r_wire->integer) return; if (!surfs->count) return; assert(r_state.blend_enabled); /** @todo - integrate BSP lighting with model lighting */ R_EnableModelLights(nullptr, 0, false, false); R_EnableColorArray(true); R_ResetArrayState(); R_EnableColorArray(false); R_EnableLighting(nullptr, false); R_EnableTexture(&texunit_lightmap, false); #ifndef GL_VERSION_ES_CM_1_0 glEnable(GL_POLYGON_OFFSET_FILL); #endif glPolygonOffset(-1.f, -1.f); glMatrixMode(GL_TEXTURE); /* some stages will manipulate texcoords */ for (i = 0; i < surfs->count; i++) { materialStage_t *s; mBspSurface_t *surf = surfs->surfaces[i]; material_t *m = &surf->texinfo->image->material; int j = -1; if (surf->frame != r_locals.frame) continue; R_UpdateMaterial(m); for (s = m->stages; s; s = s->next, j--) { if (!(s->flags & STAGE_RENDER)) continue; R_SetSurfaceStageState(surf, s); R_DrawSurfaceStage(surf, s); } } R_Color(nullptr); /* polygon offset parameters */ glPolygonOffset(0.0, 0.0); #ifndef GL_VERSION_ES_CM_1_0 glDisable(GL_POLYGON_OFFSET_FILL); #endif glLoadIdentity(); glMatrixMode(GL_MODELVIEW); R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_EnableFog(true); R_EnableColorArray(false); R_EnableTexture(&texunit_lightmap, false); R_EnableBumpmap(nullptr); R_EnableLighting(nullptr, false); R_EnableGlowMap(nullptr); R_Color(nullptr); }
/** * @brief Flares are batched by their texture. Usually, this means one draw operation * for all flares in view. Flare visibility is calculated every few millis, and * flare alpha is ramped up or down depending on the results of the visibility * trace. Flares are also faded according to the angle of their surface to the * view origin. */ void R_DrawFlareSurfaces (const mBspSurfaces_t* surfs, glElementIndex_t* indexPtr) { const image_t* image; int i, j, k, l, m; vec3_t view, verts[4]; vec3_t right, up, upright, downright; float dot, dist, scale, alpha; bool visible; bool oldblend; if (!r_flares->integer) return; if (!surfs->count) return; oldblend = r_state.blend_enabled; R_EnableColorArray(true); R_ResetArrayState(); /** @todo better GL state handling */ glDisable(GL_DEPTH_TEST); R_EnableBlend(true); R_BlendFunc(GL_SRC_ALPHA, GL_ONE); image = r_flaretextures[0]; R_BindTexture(image->texnum); j = k = l = 0; for (i = 0; i < surfs->count; i++) { mBspSurface_t* surf = surfs->surfaces[i]; mBspFlare_t* f; if (surf->frame != r_locals.frame) continue; f = surf->flare; /* bind the flare's texture */ if (f->image != image) { R_DrawArrays(0, l / 3); j = k = l = 0; refdef.batchCount++; image = f->image; R_BindTexture(image->texnum); } /* periodically test visibility to ramp alpha */ if (refdef.time - f->time > 0.02) { if (refdef.time - f->time > 0.5) /* reset old flares */ f->alpha = 0; R_Trace(refdef.viewOrigin, f->origin, 0, MASK_SOLID); visible = refdef.trace.fraction == 1.0; f->alpha += (visible ? 0.03 : -0.15); /* ramp */ if (f->alpha > 0.75) /* clamp */ f->alpha = 0.75; else if (f->alpha < 0) f->alpha = 0.0; f->time = refdef.time; } VectorSubtract(f->origin, refdef.viewOrigin, view); dist = VectorNormalize(view); /* fade according to angle */ dot = DotProduct(surf->normal, view); if (dot > 0) continue; alpha = 0.1 + -dot * r_flares->value; if (alpha > 1.0) alpha = 1.0; alpha = f->alpha * alpha; /* scale according to distance */ scale = f->radius + (f->radius * dist * .0005); VectorScale(r_locals.right, scale, right); VectorScale(r_locals.up, scale, up); VectorAdd(up, right, upright); VectorSubtract(right, up, downright); VectorSubtract(f->origin, downright, verts[0]); VectorAdd(f->origin, upright, verts[1]); VectorAdd(f->origin, downright, verts[2]); VectorSubtract(f->origin, upright, verts[3]); for (m = 0; m < 4; m++) { /* duplicate color data to all 4 verts */ memcpy(&r_state.color_array[j], f->color, sizeof(vec3_t)); r_state.color_array[j + 3] = alpha; j += 4; } /* copy texcoord info */ memcpy(&texunit_diffuse.texcoord_array[k], default_texcoords, sizeof(vec2_t) * 4); k += sizeof(vec2_t) / sizeof(vec_t) * 4; /* and lastly copy the 4 verts */ memcpy(&r_state.vertex_array_3d[l], verts, sizeof(vec3_t) * 4); l += sizeof(vec3_t) / sizeof(vec_t) * 4; } R_DrawArrays(0, l / 3); refdef.batchCount++; R_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); R_EnableBlend(oldblend); glEnable(GL_DEPTH_TEST); R_EnableColorArray(false); R_Color(nullptr); }