/* * R_EnableWarp */ void R_EnableWarp(r_program_t *program, boolean_t enable) { if (!r_programs->value) return; if (enable && (!program || !program->id)) return; if (!r_warp->value || r_state.warp_enabled == enable) return; r_state.warp_enabled = enable; R_SelectTexture(&texunit_lightmap); if (enable) { glEnable(GL_TEXTURE_2D); R_BindTexture(r_warp_image->texnum); R_UseProgram(program); } else { glDisable(GL_TEXTURE_2D); R_UseProgram(NULL); } R_SelectTexture(&texunit_diffuse); }
/* * R_EnableLighting * * Enables hardware-accelerated lighting with the specified program. This * should be called after any texture units which will be active for lighting * have been enabled. */ void R_EnableLighting(r_program_t *program, boolean_t enable) { if (!r_programs->value) return; if (enable && (!program || !program->id)) return; if (!r_lighting->value || r_state.lighting_enabled == enable) return; r_state.lighting_enabled = enable; if (enable) { // toggle state R_UseProgram(program); R_ResetLights(); glEnableClientState(GL_NORMAL_ARRAY); } else { glDisableClientState(GL_NORMAL_ARRAY); R_UseProgram(NULL); } }
/* * @brief */ static r_program_t *R_LoadProgram(const char *name, void(*Init)(void)) { r_program_t *prog; char log[MAX_STRING_CHARS]; uint32_t e; int32_t i; for (i = 0; i < MAX_PROGRAMS; i++) { prog = &r_state.programs[i]; if (!prog->id) break; } if (i == MAX_PROGRAMS) { Com_Warn("MAX_PROGRAMS reached\n"); return NULL; } g_strlcpy(prog->name, name, sizeof(prog->name)); prog->id = qglCreateProgram(); prog->v = R_LoadShader(GL_VERTEX_SHADER, va("%s_vs.glsl", name)); prog->f = R_LoadShader(GL_FRAGMENT_SHADER, va("%s_fs.glsl", name)); if (prog->v) qglAttachShader(prog->id, prog->v->id); if (prog->f) qglAttachShader(prog->id, prog->f->id); qglLinkProgram(prog->id); qglGetProgramiv(prog->id, GL_LINK_STATUS, &e); if (!e) { qglGetProgramInfoLog(prog->id, sizeof(log) - 1, NULL, log); Com_Warn("%s: %s\n", prog->name, log); R_ShutdownProgram(prog); return NULL; } prog->Init = Init; if (prog->Init) { // invoke initialization function R_UseProgram(prog); prog->Init(); R_UseProgram(NULL); } R_GetError(prog->name); return prog; }
/** * @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); }
/* * @brief */ void R_ShutdownPrograms(void) { int32_t i; if (!qglDeleteProgram) return; R_UseProgram(NULL); for (i = 0; i < MAX_PROGRAMS; i++) { if (!r_state.programs[i].id) continue; R_ShutdownProgram(&r_state.programs[i]); } }
/** * @brief blur from the source image pyramid into the dest image pyramid */ static void R_BlurStack (int levels, r_framebuffer_t **sources, r_framebuffer_t **dests) { int i; for (i = 0; i < levels; i++) { const int l = levels - i - 1; R_UseProgram(i == 0 ? default_program : r_state.combine2_program); R_UseFramebuffer(dests[l]); R_BindTextureForTexUnit(sources[l]->textures[0], &texunit_0); if (i != 0) R_BindTextureForTexUnit(dests[l + 1]->textures[0], &texunit_1); R_UseViewport(sources[l]); R_DrawQuad(); R_Blur(dests[l], sources[l], 0, 1); R_Blur(sources[l], dests[l], 0, 0); } }
r_program_t* R_LoadProgram (const char* name, programInitFunc_t init, programUseFunc_t use) { r_program_t* prog; unsigned e; int i; /* shaders are deactivated */ if (!r_programs->integer) return nullptr; /* search existing one */ for (i = 0; i < MAX_PROGRAMS; i++) { prog = &r_state.programs[i]; if (Q_streq(prog->name, name)) return prog; } /* search free slot */ for (i = 0; i < MAX_PROGRAMS; i++) { prog = &r_state.programs[i]; if (!prog->id) break; } if (i == MAX_PROGRAMS) { Com_Printf("R_LoadProgram: MAX_PROGRAMS reached.\n"); return nullptr; } Q_strncpyz(prog->name, name, sizeof(prog->name)); prog->id = qglCreateProgram(); prog->v = R_LoadShader(GL_VERTEX_SHADER, va("%s_vs.glsl", name)); prog->f = R_LoadShader(GL_FRAGMENT_SHADER, va("%s_fs.glsl", name)); if (prog->v) qglAttachShader(prog->id, prog->v->id); if (prog->f) qglAttachShader(prog->id, prog->f->id); qglLinkProgram(prog->id); qglGetProgramiv(prog->id, GL_LINK_STATUS, &e); if (!e || !prog->v || !prog->f) { char log[MAX_STRING_CHARS]; qglGetProgramInfoLog(prog->id, sizeof(log) - 1, nullptr, log); Com_Printf("R_LoadProgram: %s: %s\n", prog->name, log); R_ShutdownProgram(prog); return nullptr; } prog->init = init; if (prog->init) { /* invoke initialization function */ R_UseProgram(prog); prog->init(prog); R_UseProgram(nullptr); } prog->use = use; Com_Printf("R_LoadProgram: '%s' loaded.\n", name); return prog; }
/** * @brief handle post-processing bloom */ void R_DrawBloom (void) { int i; bool renderBufferState; if (!r_config.frameBufferObject || !r_postprocess->integer || !r_programs->integer) return; /* save state, then set up for blit-style rendering to quads */ renderBufferState = R_RenderbufferEnabled(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); #ifndef GL_VERSION_ES_CM_1_0 glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT); #endif glOrtho(0, viddef.context.width, viddef.context.height, 0, 9999.0f, SKYBOX_DEPTH); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); /* downsample into image pyramid */ R_ResolveMSAA(fbo_render); R_BindTexture(fbo_render->textures[1]); qglGenerateMipmapEXT(GL_TEXTURE_2D); R_Blur(fbo_render, fbo_bloom0, 1, 0); R_Blur(fbo_bloom0, fbo_bloom1, 0, 1); R_UseFramebuffer(r_state.buffers0[0]); R_BindTexture(fbo_bloom1->textures[0]); qglGenerateMipmapEXT(GL_TEXTURE_2D); R_UseViewport(r_state.buffers0[0]); R_DrawQuad(); for (i = 1; i < DOWNSAMPLE_PASSES; i++) { R_Blur(r_state.buffers0[i - 1], r_state.buffers1[i - 1], 0, 0); R_Blur(r_state.buffers1[i - 1], r_state.buffers2[i - 1], 0, 1); R_UseFramebuffer(r_state.buffers0[i]); R_BindTexture(r_state.buffers2[i - 1]->textures[0]); R_UseViewport(r_state.buffers0[i]); R_DrawQuad(); } /* blur and combine downsampled images */ R_BlurStack(DOWNSAMPLE_PASSES, r_state.buffers0, r_state.buffers1); /* re-combine the blurred version with the original "glow" image */ R_UseProgram(r_state.combine2_program); R_UseFramebuffer(fbo_bloom0); R_BindTextureForTexUnit(fbo_render->textures[1], &texunit_0); R_BindTextureForTexUnit(r_state.buffers1[0]->textures[0], &texunit_1); R_UseViewport(fbo_screen); R_DrawQuad(); /* draw final result to the screenbuffer */ R_UseFramebuffer(fbo_screen); R_UseProgram(r_state.combine2_program); R_BindTextureForTexUnit(fbo_render->textures[0], &texunit_0); R_BindTextureForTexUnit(fbo_bloom0->textures[0], &texunit_1); R_DrawQuad(); /* cleanup before returning */ R_UseProgram(default_program); R_CheckError(); #ifndef GL_VERSION_ES_CM_1_0 glPopAttrib(); #endif glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); R_CheckError(); /* reset renderbuffer state to what it was before */ R_EnableRenderbuffer(renderBufferState); }