void R_DrawFills (void) { if (!r_fill_arrays.vert_index) return; R_EnableTexture(&texunit_diffuse, false); R_EnableColorArray(true); /* alter the array pointers */ R_BindArray(GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, r_fill_arrays.colors); glVertexPointer(2, GL_SHORT, 0, r_fill_arrays.verts); glDrawArrays(GL_QUADS, 0, r_fill_arrays.vert_index / 2); refdef.batchCount++; /* and restore them */ R_BindDefaultArray(GL_VERTEX_ARRAY); R_BindDefaultArray(GL_COLOR_ARRAY); R_EnableColorArray(false); R_EnableTexture(&texunit_diffuse, true); r_fill_arrays.vert_index = r_fill_arrays.color_index = 0; R_Color(NULL); }
/* * @brief */ static void R_DrawChars(void) { uint16_t i; for (i = 0; i < r_draw.num_fonts; i++) { r_char_arrays_t *chars = &r_draw.char_arrays[i]; if (!chars->vert_index) continue; R_BindTexture(r_draw.fonts[i].image->texnum); R_EnableColorArray(true); // alter the array pointers R_BindArray(GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, chars->colors); R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, chars->texcoords); R_BindArray(GL_VERTEX_ARRAY, GL_SHORT, chars->verts); glDrawArrays(GL_QUADS, 0, chars->vert_index / 2); chars->color_index = 0; chars->texcoord_index = 0; chars->vert_index = 0; } // restore array pointers R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY); R_BindDefaultArray(GL_VERTEX_ARRAY); R_BindDefaultArray(GL_COLOR_ARRAY); R_EnableColorArray(false); // restore draw color R_Color(NULL); }
void R_DrawChars (void) { if (!r_char_arrays.vert_index) return; R_BindTexture(draw_chars->texnum); R_EnableColorArray(true); /* alter the array pointers */ R_BindArray(GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, r_char_arrays.colors); R_BindArray(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, r_char_arrays.texcoords); glVertexPointer(2, GL_SHORT, 0, r_char_arrays.verts); glDrawArrays(GL_QUADS, 0, r_char_arrays.vert_index / 2); refdef.batchCount++; r_char_arrays.color_index = 0; r_char_arrays.texcoord_index = 0; r_char_arrays.vert_index = 0; /* and restore them */ R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY); R_BindDefaultArray(GL_VERTEX_ARRAY); R_BindDefaultArray(GL_COLOR_ARRAY); R_EnableColorArray(false); }
/* * @brief */ static void R_DrawLines(void) { if (!r_draw.line_arrays.vert_index) return; R_EnableTexture(&texunit_diffuse, false); R_EnableColorArray(true); // alter the array pointers R_BindArray(GL_VERTEX_ARRAY, GL_SHORT, r_draw.line_arrays.verts); R_BindArray(GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, r_draw.line_arrays.colors); glDrawArrays(GL_LINES, 0, r_draw.line_arrays.vert_index / 2); // and restore them R_BindDefaultArray(GL_VERTEX_ARRAY); R_BindDefaultArray(GL_COLOR_ARRAY); R_EnableColorArray(false); R_EnableTexture(&texunit_diffuse, true); r_draw.line_arrays.vert_index = r_draw.line_arrays.color_index = 0; }
/* * R_DrawSurfacesLines_default */ static void R_DrawSurfacesLines_default(const r_bsp_surfaces_t *surfs) { unsigned int i; R_EnableTexture(&texunit_diffuse, false); R_EnableColorArray(true); R_SetArrayState(r_world_model); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); for (i = 0; i < surfs->count; i++) { if (surfs->surfaces[i]->frame != r_locals.frame) continue; R_DrawSurface_default(surfs->surfaces[i]); } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); R_EnableColorArray(false); R_EnableTexture(&texunit_diffuse, true); }
/* * @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); } }
/* * 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); }
/* * @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); }
static void R_DrawAliasTags (const mAliasModel_t *mod) { int i; const uint32_t color[] = {0xFF0000FF, 0xFF00FF00, 0xFFFF0000}; glEnable(GL_LINE_SMOOTH); R_EnableTexture(&texunit_diffuse, false); R_EnableColorArray(true); for (i = 0; i < mod->num_tags; i++) { int j; const mAliasTag_t *tag = &mod->tags[i]; for (j = 0; j < 3; j++) { vec3_t out; const mAliasTagOrientation_t *o = &tag->orient[mod->curFrame]; VectorMA(o->origin, 5, o->axis[j], out); const vec3_t points[] = { { o->origin[0], o->origin[1], o->origin[2] }, { out[0], out[1], out[2] } }; GLbyte colorArray[8]; memcpy(&colorArray[0], &color[j], 4); memcpy(&colorArray[4], &color[j], 4); R_BindArray(GL_COLOR_ARRAY, GL_UNSIGNED_BYTE, colorArray); R_BindArray(GL_VERTEX_ARRAY, GL_FLOAT, points); glDrawArrays(GL_LINE_STRIP, 0, 2); refdef.batchCount++; } } /* restore default array bindings */ R_BindDefaultArray(GL_COLOR_ARRAY); R_BindDefaultArray(GL_VERTEX_ARRAY); R_EnableColorArray(false); R_EnableTexture(&texunit_diffuse, true); glDisable(GL_LINE_SMOOTH); }
/** * @brief Draws bounding boxes for all non-linked entities in `ents`. */ static void R_DrawEntityBounds(const r_entities_t *ents, const vec4_t color) { if (!r_draw_entity_bounds->value) { return; } if (ents->count == 0) { return; } R_BindDiffuseTexture(r_image_state.null->texnum); R_EnableColorArray(true); R_BindAttributeInterleaveBuffer(&r_model_state.bound_vertice_buffer, R_ARRAY_MASK_ALL); R_BindAttributeBuffer(R_ARRAY_ELEMENTS, &r_model_state.bound_element_buffer); u8vec4_t bc; ColorDecompose(color, bc); for (int32_t i = 0; i < 8; ++i) { Vector4Set(r_model_state.bound_vertices[i].color, bc[0], bc[1], bc[2], bc[3]); } static matrix4x4_t mat, modelview; R_GetMatrix(R_MATRIX_MODELVIEW, &modelview); for (size_t i = 0; i < ents->count; i++) { const r_entity_t *e = ents->entities[i]; if (e->parent || (e->effects & EF_WEAPON) || !IS_MESH_MODEL(e->model)) { continue; } VectorSet(r_model_state.bound_vertices[0].position, e->mins[0], e->mins[1], e->mins[2]); VectorSet(r_model_state.bound_vertices[1].position, e->maxs[0], e->mins[1], e->mins[2]); VectorSet(r_model_state.bound_vertices[2].position, e->maxs[0], e->maxs[1], e->mins[2]); VectorSet(r_model_state.bound_vertices[3].position, e->mins[0], e->maxs[1], e->mins[2]); VectorSet(r_model_state.bound_vertices[4].position, e->mins[0], e->mins[1], e->maxs[2]); VectorSet(r_model_state.bound_vertices[5].position, e->maxs[0], e->mins[1], e->maxs[2]); VectorSet(r_model_state.bound_vertices[6].position, e->maxs[0], e->maxs[1], e->maxs[2]); VectorSet(r_model_state.bound_vertices[7].position, e->mins[0], e->maxs[1], e->maxs[2]); R_UploadToBuffer(&r_model_state.bound_vertice_buffer, sizeof(r_bound_interleave_vertex_t) * 8, r_model_state.bound_vertices); // draw box const vec_t *origin; if (e->effects & EF_BOB) { origin = e->termination; } else { origin = e->origin; } Matrix4x4_CreateFromEntity(&mat, origin, vec3_origin, e->scale); Matrix4x4_Concat(&mat, &modelview, &mat); R_SetMatrix(R_MATRIX_MODELVIEW, &mat); R_DrawArrays(GL_LINES, 0, (GLint) r_model_state.bound_element_count - 6); // draw origin Matrix4x4_CreateFromEntity(&mat, origin, e->angles, e->scale); Matrix4x4_Concat(&mat, &modelview, &mat); R_SetMatrix(R_MATRIX_MODELVIEW, &mat); R_DrawArrays(GL_LINES, (GLint) r_model_state.bound_element_count - 6, 6); } R_SetMatrix(R_MATRIX_MODELVIEW, &modelview); R_UnbindAttributeBuffer(R_ARRAY_ELEMENTS); R_EnableColorArray(false); 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); }