/** * @brief Clears the screens color and depth buffer */ static inline void R_Clear (void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* clear the stencil bit if shadows are enabled */ if (r_stencilshadows->integer) glClear(GL_STENCIL_BUFFER_BIT); R_CheckError(); glDepthFunc(GL_LEQUAL); R_CheckError(); glDepthRange(0.0f, 1.0f); R_CheckError(); }
/** * @brief Set the surface state according to surface flags and bind the texture * @sa R_DrawSurfaces */ static void R_SetSurfaceState (const mBspSurface_t *surf) { image_t *image; if (r_state.blend_enabled) { /* alpha blend */ vec4_t color = {1.0, 1.0, 1.0, 1.0}; switch (surf->texinfo->flags & (SURF_BLEND33 | SURF_BLEND66)) { case SURF_BLEND33: color[3] = 0.33; break; case SURF_BLEND66: color[3] = 0.66; break; } R_Color(color); } image = surf->texinfo->image; R_BindTexture(image->texnum); /* texture */ if (texunit_lightmap.enabled) { /* lightmap */ if (surf->flags & MSURF_LIGHTMAP) R_BindLightmapTexture(surf->lightmap_texnum); } R_SetSurfaceBumpMappingParameters(surf, image->normalmap, image->specularmap); R_EnableGlowMap(image->glowmap); R_CheckError(); }
/** * @brief bind specified framebuffer object so we render to it * @param[in] buf the framebuffer to use, if @c NULL the screen buffer will be used. */ void R_UseFramebuffer (const r_framebuffer_t *buf) { if (!r_config.frameBufferObject || !r_programs->integer || !r_postprocess->integer) return; if (!r_state.frameBufferObjectsInitialized) { Com_Printf("Can't bind framebuffer: framebuffers not initialized\n"); return; } if (!buf) buf = &screenBuffer; /* don't re-bind if we're already using the requested buffer */ if (buf == r_state.activeFramebuffer) return; qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo); /* don't call glDrawBuffers for main screenbuffer */ /** @todo buf != &screenBuffer */ if (buf->nTextures > 0) qglDrawBuffers(buf->nTextures, colorAttachments); glClearColor(r_state.activeFramebuffer->clearColor[0], r_state.activeFramebuffer->clearColor[1], r_state.activeFramebuffer->clearColor[2], r_state.activeFramebuffer->clearColor[3]); glClear(GL_COLOR_BUFFER_BIT | (buf->depth ? GL_DEPTH_BUFFER_BIT : 0)); r_state.activeFramebuffer = buf; R_CheckError(); }
static void R_ShutdownProgram (r_program_t* prog) { if (prog->v) { qglDetachShader(prog->id, prog->v->id); R_ShutdownShader(prog->v); R_CheckError(); } if (prog->f) { qglDetachShader(prog->id, prog->f->id); R_ShutdownShader(prog->f); R_CheckError(); } qglDeleteProgram(prog->id); OBJZERO(*prog); }
void R_InitFBObjects (void) { unsigned int filters[2]; float scales[DOWNSAMPLE_PASSES]; int i; if (!r_config.frameBufferObject || !r_programs->integer) return; frameBufferObjectCount = 0; OBJZERO(frameBufferObjects); OBJZERO(frameBufferTextures); r_state.frameBufferObjectsInitialized = true; for (i = 0; i < DOWNSAMPLE_PASSES; i++) scales[i] = powf(DOWNSAMPLE_SCALE, i + 1); /* setup default screen framebuffer */ screenBuffer.fbo = 0; screenBuffer.depth = 0; screenBuffer.nTextures = 0; screenBuffer.width = viddef.context.width; screenBuffer.height = viddef.context.height; R_SetupViewport(&screenBuffer, 0, 0, viddef.context.width, viddef.context.height); Vector4Clear(screenBuffer.clearColor); /* use default framebuffer */ qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); r_state.activeFramebuffer = &screenBuffer; colorAttachments = Mem_AllocTypeN(GLenum, r_config.maxDrawBuffers); for (i = 0; i < r_config.maxDrawBuffers; i++) colorAttachments[i] = GL_COLOR_ATTACHMENT0_EXT + i; filters[0] = GL_NEAREST; filters[1] = GL_LINEAR_MIPMAP_LINEAR; /* setup main 3D render target */ r_state.renderBuffer = R_CreateFramebuffer(viddef.context.width, viddef.context.height, 2, true, false, filters); /* setup bloom render targets */ fbo_bloom0 = R_CreateFramebuffer(viddef.context.width, viddef.context.height, 1, false, false, filters); fbo_bloom1 = R_CreateFramebuffer(viddef.context.width, viddef.context.height, 1, false, false, filters); filters[0] = GL_LINEAR; /* setup extra framebuffers */ for (i = 0; i < DOWNSAMPLE_PASSES; i++) { const int h = (int)((float)viddef.context.height / scales[i]); const int w = (int)((float)viddef.context.width / scales[i]); r_state.buffers0[i] = R_CreateFramebuffer(w, h, 1, false, false, filters); r_state.buffers1[i] = R_CreateFramebuffer(w, h, 1, false, false, filters); r_state.buffers2[i] = R_CreateFramebuffer(w, h, 1, false, false, filters); R_CheckError(); } }
static void R_UploadLightmapBlock (void) { #ifdef GL_VERSION_ES_CM_1_0 const int texFormat = GL_RGB; #else const int texFormat = r_config.gl_compressed_solid_format ? r_config.gl_compressed_solid_format : r_config.gl_solid_format; #endif GLuint texid; if (r_lightmaps.lightmap_count >= MAX_GL_LIGHTMAPS) { Com_Printf("R_UploadLightmapBlock: MAX_GL_LIGHTMAPS reached.\n"); return; } if (!r_lightmaps.incomplete_atlas) { glGenTextures(1, &texid); r_lightmaps.lightmap_texnums[r_lightmaps.lightmap_count++] = texid; } else { texid = r_lightmaps.lightmap_texnums[r_lightmaps.lightmap_count]; } R_BindTexture(texid); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, texFormat, r_lightmaps.size, r_lightmaps.size, 0, GL_RGB, GL_UNSIGNED_BYTE, r_lightmaps.sample_buffer); R_CheckError(); if (r_lightmaps.deluxemap_count >= MAX_GL_DELUXEMAPS) { Com_Printf("R_UploadLightmapBlock: MAX_GL_DELUXEMAPS reached.\n"); return; } if (!r_lightmaps.incomplete_atlas) { glGenTextures(1, &texid); r_lightmaps.deluxemap_texnums[r_lightmaps.deluxemap_count++] = texid; } else { texid = r_lightmaps.deluxemap_texnums[r_lightmaps.deluxemap_count]; } R_BindTexture(texid); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, texFormat, r_lightmaps.size, r_lightmaps.size, 0, GL_RGB, GL_UNSIGNED_BYTE, r_lightmaps.direction_buffer); /* clear the allocation block and buffers */ memset(r_lightmaps.allocated, 0, r_lightmaps.size * sizeof(unsigned)); memset(r_lightmaps.sample_buffer, 0, r_lightmaps.size * r_lightmaps.size * sizeof(unsigned)); memset(r_lightmaps.direction_buffer, 0, r_lightmaps.size * r_lightmaps.size * sizeof(unsigned)); r_lightmaps.incomplete_atlas = false; }
/** * @brief Uploads image data * @param[in] name The name of the texture to use for this data * @param[in] frame The frame data that is uploaded * @param[in] width The width of the texture * @param[in] height The height of the texture * @return the texture number of the uploaded images */ int R_UploadData (const char *name, byte *frame, int width, int height) { image_t *img; unsigned *scaled; int scaledWidth, scaledHeight; int samples = r_config.gl_compressed_solid_format ? r_config.gl_compressed_solid_format : r_config.gl_solid_format; int i, c; byte *scan; R_GetScaledTextureSize(width, height, &scaledWidth, &scaledHeight); img = R_FindImage(name, it_pic); if (img == r_noTexture) Com_Error(ERR_FATAL, "Could not find the searched image: %s", name); /* scan the texture for any non-255 alpha */ c = scaledWidth * scaledHeight; /* set scan to the first alpha byte */ for (i = 0, scan = ((byte *) frame) + 3; i < c; i++, scan += 4) { if (*scan != 255) { samples = r_config.gl_compressed_alpha_format ? r_config.gl_compressed_alpha_format : r_config.gl_alpha_format; break; } } if (scaledWidth != width || scaledHeight != height) { /* whereas others need to be scaled */ scaled = (unsigned *)Mem_PoolAllocExt(scaledWidth * scaledHeight * sizeof(unsigned), qfalse, vid_imagePool, 0); R_ScaleTexture((unsigned *)frame, width, height, scaled, scaledWidth, scaledHeight); } else { scaled = (unsigned *)frame; } R_BindTexture(img->texnum); if (img->upload_width == scaledWidth && img->upload_height == scaledHeight) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, scaledWidth, scaledHeight, GL_RGBA, GL_UNSIGNED_BYTE, scaled); } else { /* Reallocate the texture */ img->width = width; img->height = height; img->upload_width = scaledWidth; img->upload_height = scaledHeight; #ifdef HAVE_GLES glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, scaledWidth, scaledHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); #else glTexImage2D(GL_TEXTURE_2D, 0, samples, scaledWidth, scaledHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); #endif } glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); R_CheckError(); if (scaled != (unsigned *)frame) Mem_Free(scaled); return img->texnum; }
/** * @brief Forces multisample antialiasing resolve on given framebuffer, if needed * @param[in] buf the framebuffer to use */ void R_ResolveMSAA (const r_framebuffer_t *buf) { int i; if (!buf->samples) return; qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT,buf->fbo); qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,buf->proxyFBO); for (i = 0; i < buf->nTextures; i++) { glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + i); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + i); qglBlitFramebuffer(0, 0, buf->width, buf-> height, 0, 0, buf->width, buf->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); R_CheckError(); } R_CheckError(); qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, screenBuffer.fbo); R_CheckError(); }
void R_SetupFrustum (void) { int i; /* build the transformation matrix for the given view angles */ AngleVectors(refdef.viewAngles, r_locals.forward, r_locals.right, r_locals.up); #if 0 /* if we are not drawing world model, we are on the UI code. It break the default UI SCISSOR * Anyway we should merge that code into R_CleanupDepthBuffer (with some rework), it looks better */ /* clear out the portion of the screen that the NOWORLDMODEL defines */ if (refdef.rendererFlags & RDF_NOWORLDMODEL) { glEnable(GL_SCISSOR_TEST); glScissor(viddef.x, viddef.height - viddef.viewHeight - viddef.y, viddef.viewWidth, viddef.viewHeight); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); R_CheckError(); glDisable(GL_SCISSOR_TEST); } #endif if (r_isometric->integer) { /* 4 planes of a cube */ VectorScale(r_locals.right, +1, r_locals.frustum[0].normal); VectorScale(r_locals.right, -1, r_locals.frustum[1].normal); VectorScale(r_locals.up, +1, r_locals.frustum[2].normal); VectorScale(r_locals.up, -1, r_locals.frustum[3].normal); for (i = 0; i < 4; i++) { r_locals.frustum[i].type = PLANE_ANYZ; r_locals.frustum[i].dist = DotProduct(refdef.viewOrigin, r_locals.frustum[i].normal); } r_locals.frustum[0].dist -= 10 * refdef.fieldOfViewX; r_locals.frustum[1].dist -= 10 * refdef.fieldOfViewX; r_locals.frustum[2].dist -= 10 * refdef.fieldOfViewX * ((float) viddef.viewHeight / viddef.viewWidth); r_locals.frustum[3].dist -= 10 * refdef.fieldOfViewX * ((float) viddef.viewHeight / viddef.viewWidth); } else { /* rotate VPN right by FOV_X/2 degrees */ RotatePointAroundVector(r_locals.frustum[0].normal, r_locals.up, r_locals.forward, -(90 - refdef.fieldOfViewX / 2)); /* rotate VPN left by FOV_X/2 degrees */ RotatePointAroundVector(r_locals.frustum[1].normal, r_locals.up, r_locals.forward, 90 - refdef.fieldOfViewX / 2); /* rotate VPN up by FOV_X/2 degrees */ RotatePointAroundVector(r_locals.frustum[2].normal, r_locals.right, r_locals.forward, 90 - refdef.fieldOfViewY / 2); /* rotate VPN down by FOV_X/2 degrees */ RotatePointAroundVector(r_locals.frustum[3].normal, r_locals.right, r_locals.forward, -(90 - refdef.fieldOfViewY / 2)); for (i = 0; i < 4; i++) { r_locals.frustum[i].type = PLANE_ANYZ; r_locals.frustum[i].dist = DotProduct(refdef.viewOrigin, r_locals.frustum[i].normal); } } }
bool R_Init (void) { R_RegisterSystemVars(); OBJZERO(r_state); OBJZERO(r_locals); OBJZERO(r_config); /* some config default values */ r_config.gl_solid_format = GL_RGB; r_config.gl_alpha_format = GL_RGBA; r_config.gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; r_config.gl_filter_max = GL_LINEAR; r_config.maxTextureSize = 256; /* initialize OS-specific parts of OpenGL */ if (!Rimp_Init()) return false; /* get our various GL strings */ r_config.vendorString = (const char *)glGetString(GL_VENDOR); r_config.rendererString = (const char *)glGetString(GL_RENDERER); r_config.versionString = (const char *)glGetString(GL_VERSION); r_config.extensionsString = (const char *)glGetString(GL_EXTENSIONS); R_Strings_f(); /* sanity checks and card specific hacks */ R_VerifyDriver(); R_EnforceVersion(); R_RegisterImageVars(); /* prevent reloading of some rendering cvars */ Cvar_ClearVars(CVAR_R_MASK); R_InitExtensions(); R_SetDefaultState(); R_InitPrograms(); R_InitImages(); R_InitMiscTexture(); R_DrawInitLocal(); R_SphereInit(); R_FontInit(); R_InitFBObjects(); R_UpdateDefaultMaterial("","","", NULL); R_CheckError(); return true; }
/** * @brief Animated model render function * @see R_DrawAliasStatic */ static void R_DrawAliasFrameLerp (mAliasModel_t* mod, mAliasMesh_t *mesh, float backlerp, int framenum, int oldframenum, const vec4_t shellColor) { R_FillArrayData(mod, mesh, backlerp, framenum, oldframenum, false); R_EnableAnimation(mesh, backlerp, true); glDrawArrays(GL_TRIANGLES, 0, mesh->num_tris * 3); refdef.batchCount++; R_DrawMeshModelShell(mesh, shellColor); R_EnableAnimation(NULL, 0.0, false); R_CheckError(); }
/** * @brief Render the specified stage for the surface. Resolve vertex attributes via * helper functions, outputting to the default vertex arrays. */ static void R_DrawSurfaceStage (mBspSurface_t *surf, materialStage_t *stage) { int i; R_ReallocateStateArrays(surf->numedges); R_ReallocateTexunitArray(&texunit_diffuse, surf->numedges); R_ReallocateTexunitArray(&texunit_lightmap, surf->numedges); for (i = 0; i < surf->numedges; i++) { const float *v = &r_mapTiles[surf->tile]->bsp.verts[surf->index * 3 + i * 3]; const float *st = &r_mapTiles[surf->tile]->bsp.texcoords[surf->index * 2 + i * 2]; R_StageVertex(surf, stage, v, &r_state.vertex_array_3d[i * 3]); R_StageTexCoord(stage, v, st, &texunit_diffuse.texcoord_array[i * 2]); if (texunit_lightmap.enabled) { st = &r_mapTiles[surf->tile]->bsp.lmtexcoords[surf->index * 2 + i * 2]; texunit_lightmap.texcoord_array[i * 2 + 0] = st[0]; texunit_lightmap.texcoord_array[i * 2 + 1] = st[1]; } if (r_state.color_array_enabled) R_StageColor(stage, v, &r_state.color_array[i * 4]); /* normals and tangents */ if (r_state.lighting_enabled) { const float *n = &r_mapTiles[surf->tile]->bsp.normals[surf->index * 3 + i * 3]; memcpy(&r_state.normal_array[i * 3], n, sizeof(vec3_t)); if (r_state.active_normalmap) { const float *t = &r_mapTiles[surf->tile]->bsp.tangents[surf->index * 4 + i * 4]; memcpy(&r_state.tangent_array[i * 4], t, sizeof(vec3_t)); } } } glDrawArrays(GL_TRIANGLE_FAN, 0, i); refdef.batchCount++; R_CheckError(); }
/** * @sa R_BeginFrame * @sa R_EndFrame */ void R_RenderFrame (void) { R_Setup3D(); /* activate wire mode */ if (r_wire->integer) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (!(refdef.rendererFlags & RDF_NOWORLDMODEL)) { int tile; if (r_threads->integer) { while (r_threadstate.state != THREAD_RENDERER) Sys_Sleep(0); r_threadstate.state = THREAD_CLIENT; } else { R_SetupFrustum(); /* draw brushes on current worldlevel */ R_GetLevelSurfaceLists(); } R_UpdateSustainedLights(); R_CheckError(); for (tile = 0; tile < r_numMapTiles; tile++) { const model_t *mapTile = r_mapTiles[tile]; const mBspModel_t *bsp = &mapTile->bsp; R_AddBspRRef(bsp, vec3_origin, vec3_origin, false); } R_GetEntityLists(); R_EnableFog(true); R_RenderOpaqueBspRRefs(); R_RenderOpaqueWarpBspRRefs(); R_DrawOpaqueMeshEntities(r_opaque_mesh_entities); R_RenderAlphaTestBspRRefs(); R_EnableBlend(true); R_RenderMaterialBspRRefs(); R_EnableFog(false); R_RenderBlendBspRRefs(); R_RenderBlendWarpBspRRefs(); R_DrawBlendMeshEntities(r_blend_mesh_entities); R_EnableFog(true); R_RenderFlareBspRRefs(); R_EnableFog(false); if (r_debug_lights->integer) { int i; for (i = 0; i < refdef.numStaticLights; i++) { const light_t *l = &refdef.staticLights[i]; R_AddCorona(l->origin, l->radius, l->color); } for (i = 0; i < refdef.numDynamicLights; i++) { const light_t *l = &refdef.dynamicLights[i]; R_AddCorona(l->origin, l->radius, l->color); } } R_DrawCoronas(); R_EnableBlend(false); for (tile = 0; tile < r_numMapTiles; tile++) { R_DrawBspNormals(tile); } R_Color(NULL); R_DrawSpecialEntities(r_special_entities); R_DrawNullEntities(r_null_entities); R_DrawEntityEffects(); } else { glClear(GL_DEPTH_BUFFER_BIT); R_GetEntityLists(); R_RenderOpaqueBspRRefs(); R_RenderOpaqueWarpBspRRefs(); R_DrawOpaqueMeshEntities(r_opaque_mesh_entities); R_RenderAlphaTestBspRRefs(); R_EnableBlend(true); R_RenderMaterialBspRRefs(); R_RenderBlendBspRRefs(); R_RenderBlendWarpBspRRefs(); R_DrawBlendMeshEntities(r_blend_mesh_entities); R_RenderFlareBspRRefs(); R_EnableBlend(false); R_Color(NULL); R_DrawSpecialEntities(r_special_entities); R_DrawNullEntities(r_null_entities); R_DrawEntityEffects(); } R_EnableBlend(true); R_DrawParticles(); R_EnableBlend(false); /* leave wire mode again */ if (r_wire->integer) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); R_DrawBloom(); R_DrawBoundingBoxes(); R_ResetArrayState(); /* go back into 2D mode for hud and the like */ R_Setup2D(); R_CheckError(); }
/** * @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); }
/** * @brief Draws a model in 2d mode (for rendering model data from the ui) * @param[in,out] mi All the needed model information to render the model * @param[in,out] pmi The model information of the parent model. This is used * in those cases, where the model that should get rendered here is placed relativly * to an already existing model in the world. * @param[in] tagname If a parent model is given, a @c tagname is given in most cases, too. It's used * to transform the model location relative to the parent model location again. E.g. a * @c tagname of tag_rweapon will transform the location to the right hand of an actor. * @sa R_DrawAliasModel */ void R_DrawModelDirect (modelInfo_t * mi, modelInfo_t * pmi, const char *tagname) { image_t *skin; mAliasMesh_t *mesh; if (Q_strnull(mi->name)) return; /* register the model */ mi->model = R_FindModel(mi->name); /* check if the model exists */ if (!mi->model) { Com_Printf("No model found for '%s'\n", mi->name); return; } skin = R_AliasModelState(mi->model, &mi->mesh, &mi->frame, &mi->oldframe, &mi->skin); if (skin == NULL) { Com_Printf("Model '%s' is broken\n", mi->name); return; } glPushMatrix(); glScalef(viddef.rx, viddef.ry, (viddef.rx + viddef.ry) / 2); R_Color(mi->color); if (pmi) { /* register the parent model */ pmi->model = R_FindModel(pmi->name); /* transform - the next transform for the child model will be relative from the * parent model location now */ R_TransformModelDirect(pmi); /* tag transformation */ if (tagname) { const mAliasTagOrientation_t *current = NULL; const mAliasTagOrientation_t *old = NULL; R_GetTags(pmi->model, tagname, pmi->frame, pmi->oldframe, ¤t, &old); if (current != NULL && old != NULL) { float interpolated[16]; /* do interpolation */ R_InterpolateTransform(pmi->backlerp, pmi->model->alias.num_frames, current, old, interpolated); /* transform */ glMultMatrixf(interpolated); R_CheckError(); } } } /* transform */ R_TransformModelDirect(mi); /* we have to reenable this here - we are in 2d mode here already */ glEnable(GL_DEPTH_TEST); /* draw it */ R_BindTexture(skin->texnum); /* draw the model */ mesh = &mi->model->alias.meshes[0]; refdef.aliasCount += mesh->num_tris; if (mi->model->alias.num_frames == 1) R_DrawAliasStaticWithReset(mesh, vec4_origin); else R_DrawAliasFrameLerp(&mi->model->alias, mesh, mi->backlerp, mi->frame, mi->oldframe, vec4_origin); /* show model bounding box */ if (r_showbox->integer) R_DrawBoundingBox(mi->model->alias.frames[mi->frame].mins, mi->model->alias.frames[mi->frame].maxs); glDisable(GL_DEPTH_TEST); glPopMatrix(); R_Color(NULL); }
/** * @brief create a new framebuffer object * @param[in] width The width of the framebuffer * @param[in] height The height of the framebuffer * @param[in] ntextures The amount of textures for this framebuffer. See also the filters array. * @param[in] depth Also generate a depth buffer * @param[in] halfFloat Use half float pixel format * @param[in] filters Filters for the textures. Must have @c ntextures entries */ r_framebuffer_t * R_CreateFramebuffer (int width, int height, int ntextures, bool depth, bool halfFloat, unsigned int *filters) { r_framebuffer_t *buf; int i; if (!r_state.frameBufferObjectsInitialized) { Com_Printf("Warning: framebuffer creation failed; framebuffers not initialized!\n"); return NULL; } if (frameBufferObjectCount >= lengthof(frameBufferObjects)) { Com_Printf("Warning: framebuffer creation failed; already created too many framebuffers!\n"); return NULL; } buf = &frameBufferObjects[frameBufferObjectCount++]; OBJZERO(*buf); if (ntextures > r_config.maxDrawBuffers) { Com_Printf("Couldn't allocate requested number of drawBuffers in R_SetupFramebuffer!\n"); ntextures = r_config.maxDrawBuffers; } Vector4Clear(buf->clearColor); buf->width = width; buf->height = height; R_SetupViewport(buf, 0, 0, width, height); buf->nTextures = ntextures; buf->textures = Mem_AllocTypeN(unsigned int, ntextures); buf->pixelFormat = halfFloat ? GL_RGBA16F_ARB : GL_RGBA8; buf->byteFormat = halfFloat ? GL_HALF_FLOAT_ARB : GL_UNSIGNED_BYTE; /* Presence of depth buffer indicates render target that could use antialiasing*/ if (depth) { /** @todo also check if we are running on older (SM2.0) hardware, which doesn't support antialiased MRT */ if (qglRenderbufferStorageMultisampleEXT && qglBlitFramebuffer) { int samples = std::min(4, std::max(0, r_multisample->integer)); if (samples>1) buf->samples = samples; } } for (i = 0; i < buf->nTextures; i++) { buf->textures[i] = R_GetFreeFBOTexture(); glBindTexture(GL_TEXTURE_2D, buf->textures[i]); glTexImage2D(GL_TEXTURE_2D, 0, buf->pixelFormat, buf->width, buf->height, 0, GL_RGBA, buf->byteFormat, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filters[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); qglGenerateMipmapEXT(GL_TEXTURE_2D); if (r_config.anisotropic) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_config.maxAnisotropic); R_CheckError(); } glBindTexture(GL_TEXTURE_2D, 0); /* create FBO itself */ qglGenFramebuffersEXT(1, &buf->fbo); R_CheckError(); qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->fbo); /* create&attach depth renderbuffer */ if (depth) { qglGenRenderbuffersEXT(1, &buf->depth); qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->depth); if (buf->samples) qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, buf->samples, GL_DEPTH_COMPONENT, buf->width, buf->height); else qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, buf->width, buf->height); qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buf->depth); } else { buf->depth = 0; } /* create multisample color buffers if needed */ if (buf->samples) { /* generate color buffers */ for (i = 0; i < buf->nTextures; i++) { unsigned colorbuffer; qglGenRenderbuffersEXT(1, &colorbuffer); qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorbuffer); qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, buf->samples, buf->pixelFormat, buf->width, buf->height); qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_RENDERBUFFER_EXT, colorbuffer); R_CheckError(); } /* proxy framebuffer object for resolving MSAA */ qglGenFramebuffersEXT(1, &buf->proxyFBO); R_CheckError(); qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buf->proxyFBO); } /* Whether multisampling was enabled or not, current FBO should be populated with render-to-texture bindings */ for (i = 0; i < buf->nTextures; i++) { qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, colorAttachments[i], GL_TEXTURE_2D, buf->textures[i], 0); R_CheckError(); } R_CheckError(); /* unbind the framebuffer and return to default state */ qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); return buf; }
/** * Take a screenshot of the frame buffer * @param[in] x * @param[in] y * @param[in] width * @param[in] height * @param[in] filename Force to use a filename. Else NULL to autogen a filename * @param[in] ext Force to use an image format (tga/png/jpg). Else NULL to use value of r_screenshot_format */ void R_ScreenShot (int x, int y, int width, int height, const char *filename, const char *ext) { char checkName[MAX_OSPATH]; int type, shotNum, quality = 100; qFILE f; int rowPack; glGetIntegerv(GL_PACK_ALIGNMENT, &rowPack); glPixelStorei(GL_PACK_ALIGNMENT, 1); /* Find out what format to save in */ if (ext == NULL) ext = r_screenshot_format->string; if (!Q_strcasecmp(ext, "png")) type = SSHOTTYPE_PNG; else if (!Q_strcasecmp(ext, "jpg")) type = SSHOTTYPE_JPG; else type = SSHOTTYPE_TGA_COMP; /* Set necessary values */ switch (type) { case SSHOTTYPE_TGA_COMP: Com_Printf("Taking TGA screenshot...\n"); ext = "tga"; break; case SSHOTTYPE_PNG: Com_Printf("Taking PNG screenshot...\n"); ext = "png"; break; case SSHOTTYPE_JPG: if (Cmd_Argc() == 3) quality = atoi(Cmd_Argv(2)); else quality = r_screenshot_jpeg_quality->integer; if (quality > 100 || quality <= 0) quality = 100; Com_Printf("Taking JPG screenshot (at %i%% quality)...\n", quality); ext = "jpg"; break; } /* Find a file name to save it to */ if (filename) { Com_sprintf(checkName, sizeof(checkName), "scrnshot/%s.%s", filename, ext); } else { for (shotNum = 0; shotNum < 1000; shotNum++) { Com_sprintf(checkName, sizeof(checkName), "scrnshot/ufo%i%i.%s", shotNum / 10, shotNum % 10, ext); if (FS_CheckFile("%s", checkName) == -1) break; } if (shotNum == 1000) { Com_Printf("R_ScreenShot_f: screenshot limit (of 1000) exceeded!\n"); return; } } /* Open it */ FS_OpenFile(checkName, &f, FILE_WRITE); if (!f.f) { Com_Printf("R_ScreenShot_f: Couldn't create file: %s\n", checkName); return; } /* Allocate room for a copy of the framebuffer */ byte* const buffer = Mem_PoolAllocTypeN(byte, width * height * 3, vid_imagePool); if (!buffer) { Com_Printf("R_ScreenShot_f: Could not allocate %i bytes for screenshot!\n", width * height * 3); FS_CloseFile(&f); return; } /* Read the framebuffer into our storage */ glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer); R_CheckError(); /* Write */ switch (type) { case SSHOTTYPE_TGA_COMP: R_WriteCompressedTGA(&f, buffer, width, height); break; case SSHOTTYPE_PNG: R_WritePNG(&f, buffer, width, height); break; case SSHOTTYPE_JPG: R_WriteJPG(&f, buffer, width, height, quality); break; } /* Finish */ FS_CloseFile(&f); Mem_Free(buffer); Com_Printf("Wrote %s to %s\n", checkName, FS_Gamedir()); glPixelStorei(GL_PACK_ALIGNMENT, rowPack); }
/** * @brief Check and load all needed and supported opengl extensions * @sa R_Init */ static void R_InitExtensions (void) { GLenum err; int tmpInteger; /* Get OpenGL version.*/ sscanf(r_config.versionString, "%d.%d", &r_config.glVersionMajor, &r_config.glVersionMinor); /* multitexture */ qglActiveTexture = NULL; qglClientActiveTexture = NULL; /* vertex buffer */ qglGenBuffers = NULL; qglDeleteBuffers = NULL; qglBindBuffer = NULL; qglBufferData = NULL; /* glsl */ qglCreateShader = NULL; qglDeleteShader = NULL; qglShaderSource = NULL; qglCompileShader = NULL; qglGetShaderiv = NULL; qglGetShaderInfoLog = NULL; qglCreateProgram = NULL; qglDeleteProgram = NULL; qglAttachShader = NULL; qglDetachShader = NULL; qglLinkProgram = NULL; qglUseProgram = NULL; qglGetActiveUniform = NULL; qglGetProgramiv = NULL; qglGetProgramInfoLog = NULL; qglGetUniformLocation = NULL; qglUniform1i = NULL; qglUniform1f = NULL; qglUniform1fv = NULL; qglUniform2fv = NULL; qglUniform3fv = NULL; qglUniform4fv = NULL; qglGetAttribLocation = NULL; qglUniformMatrix4fv = NULL; /* vertex attribute arrays */ qglEnableVertexAttribArray = NULL; qglDisableVertexAttribArray = NULL; qglVertexAttribPointer = NULL; /* framebuffer objects */ qglIsRenderbufferEXT = NULL; qglBindRenderbufferEXT = NULL; qglDeleteRenderbuffersEXT = NULL; qglGenRenderbuffersEXT = NULL; qglRenderbufferStorageEXT = NULL; qglRenderbufferStorageMultisampleEXT = NULL; qglGetRenderbufferParameterivEXT = NULL; qglIsFramebufferEXT = NULL; qglBindFramebufferEXT = NULL; qglDeleteFramebuffersEXT = NULL; qglGenFramebuffersEXT = NULL; qglCheckFramebufferStatusEXT = NULL; qglFramebufferTexture1DEXT = NULL; qglFramebufferTexture2DEXT = NULL; qglFramebufferTexture3DEXT = NULL; qglFramebufferRenderbufferEXT = NULL; qglGetFramebufferAttachmentParameterivEXT = NULL; qglGenerateMipmapEXT = NULL; qglDrawBuffers = NULL; /* multitexture */ if (R_CheckExtension("GL_ARB_multitexture")) { qglActiveTexture = (ActiveTexture_t)R_GetProcAddress("glActiveTexture"); qglClientActiveTexture = (ClientActiveTexture_t)R_GetProcAddress("glClientActiveTexture"); } if (R_CheckExtension("GL_ARB_texture_compression")) { if (r_ext_texture_compression->integer) { Com_Printf("using GL_ARB_texture_compression\n"); if (r_ext_s3tc_compression->integer && strstr(r_config.extensionsString, "GL_EXT_texture_compression_s3tc")) { r_config.gl_compressed_solid_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; r_config.gl_compressed_alpha_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; } else { r_config.gl_compressed_solid_format = GL_COMPRESSED_RGB_ARB; r_config.gl_compressed_alpha_format = GL_COMPRESSED_RGBA_ARB; } } } if (R_CheckExtension("GL_ARB_texture_non_power_of_two")) { if (r_ext_nonpoweroftwo->integer) { Com_Printf("using GL_ARB_texture_non_power_of_two\n"); r_config.nonPowerOfTwo = true; } else { r_config.nonPowerOfTwo = false; Com_Printf("ignoring GL_ARB_texture_non_power_of_two\n"); } } else { if (R_CheckGLVersion(2, 0)) { r_config.nonPowerOfTwo = r_ext_nonpoweroftwo->integer == 1; } else { r_config.nonPowerOfTwo = false; } } /* anisotropy */ if (R_CheckExtension("GL_EXT_texture_filter_anisotropic")) { if (r_anisotropic->integer) { glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &r_config.maxAnisotropic); R_CheckError(); if (r_anisotropic->integer > r_config.maxAnisotropic) { Com_Printf("max GL_EXT_texture_filter_anisotropic value is %i\n", r_config.maxAnisotropic); Cvar_SetValue("r_anisotropic", r_config.maxAnisotropic); } if (r_config.maxAnisotropic) r_config.anisotropic = true; } } if (R_CheckExtension("GL_EXT_texture_lod_bias")) r_config.lod_bias = true; /* vertex buffer objects */ if (R_CheckExtension("GL_ARB_vertex_buffer_object")) { qglGenBuffers = (GenBuffers_t)R_GetProcAddress("glGenBuffers"); qglDeleteBuffers = (DeleteBuffers_t)R_GetProcAddress("glDeleteBuffers"); qglBindBuffer = (BindBuffer_t)R_GetProcAddress("glBindBuffer"); qglBufferData = (BufferData_t)R_GetProcAddress("glBufferData"); glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &r_config.maxVertexBufferSize); Com_Printf("using GL_ARB_vertex_buffer_object\nmax vertex buffer size: %i\n", r_config.maxVertexBufferSize); } /* glsl vertex and fragment shaders and programs */ if (R_CheckExtension("GL_ARB_fragment_shader")) { qglCreateShader = (CreateShader_t)R_GetProcAddress("glCreateShader"); qglDeleteShader = (DeleteShader_t)R_GetProcAddress("glDeleteShader"); qglShaderSource = (ShaderSource_t)R_GetProcAddress("glShaderSource"); qglCompileShader = (CompileShader_t)R_GetProcAddress("glCompileShader"); qglGetShaderiv = (GetShaderiv_t)R_GetProcAddress("glGetShaderiv"); qglGetShaderInfoLog = (GetShaderInfoLog_t)R_GetProcAddress("glGetShaderInfoLog"); qglCreateProgram = (CreateProgram_t)R_GetProcAddress("glCreateProgram"); qglDeleteProgram = (DeleteProgram_t)R_GetProcAddress("glDeleteProgram"); qglAttachShader = (AttachShader_t)R_GetProcAddress("glAttachShader"); qglDetachShader = (DetachShader_t)R_GetProcAddress("glDetachShader"); qglLinkProgram = (LinkProgram_t)R_GetProcAddress("glLinkProgram"); qglUseProgram = (UseProgram_t)R_GetProcAddress("glUseProgram"); qglGetActiveUniform = (GetActiveUniforms_t)R_GetProcAddress("glGetActiveUniform"); qglGetProgramiv = (GetProgramiv_t)R_GetProcAddress("glGetProgramiv"); qglGetProgramInfoLog = (GetProgramInfoLog_t)R_GetProcAddress("glGetProgramInfoLog"); qglGetUniformLocation = (GetUniformLocation_t)R_GetProcAddress("glGetUniformLocation"); qglUniform1i = (Uniform1i_t)R_GetProcAddress("glUniform1i"); qglUniform1f = (Uniform1f_t)R_GetProcAddress("glUniform1f"); qglUniform1fv = (Uniform1fv_t)R_GetProcAddress("glUniform1fv"); qglUniform2fv = (Uniform2fv_t)R_GetProcAddress("glUniform2fv"); qglUniform3fv = (Uniform3fv_t)R_GetProcAddress("glUniform3fv"); qglUniform4fv = (Uniform4fv_t)R_GetProcAddress("glUniform4fv"); qglGetAttribLocation = (GetAttribLocation_t)R_GetProcAddress("glGetAttribLocation"); qglUniformMatrix4fv = (UniformMatrix4fv_t)R_GetProcAddress("glUniformMatrix4fv"); /* vertex attribute arrays */ qglEnableVertexAttribArray = (EnableVertexAttribArray_t)R_GetProcAddress("glEnableVertexAttribArray"); qglDisableVertexAttribArray = (DisableVertexAttribArray_t)R_GetProcAddress("glDisableVertexAttribArray"); qglVertexAttribPointer = (VertexAttribPointer_t)R_GetProcAddress("glVertexAttribPointer"); } if (R_CheckExtension("GL_ARB_shading_language_100") || r_config.glVersionMajor >= 2) { /* The GL_ARB_shading_language_100 extension was added to core specification since OpenGL 2.0; * it is ideally listed in the extensions for backwards compatibility. If it isn't there and OpenGL > v2.0 * then enable shaders as the implementation supports the shading language!*/ const char *shadingVersion = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION); sscanf(shadingVersion, "%d.%d", &r_config.glslVersionMajor, &r_config.glslVersionMinor); Com_Printf("GLSL version guaranteed to be supported by OpenGL implementation postfixed by vender supplied info: %i.%i\n", r_config.glslVersionMajor, r_config.glslVersionMinor); } else { /* The shading language is not supported.*/ Com_Printf("GLSL shaders unsupported by OpenGL implementation.\n"); } /* framebuffer objects */ if (R_CheckExtension("GL_###_framebuffer_object")) { qglIsRenderbufferEXT = (IsRenderbufferEXT_t)R_GetProcAddressExt("glIsRenderbuffer###"); qglBindRenderbufferEXT = (BindRenderbufferEXT_t)R_GetProcAddressExt("glBindRenderbuffer###"); qglDeleteRenderbuffersEXT = (DeleteRenderbuffersEXT_t)R_GetProcAddressExt("glDeleteRenderbuffers###"); qglGenRenderbuffersEXT = (GenRenderbuffersEXT_t)R_GetProcAddressExt("glGenRenderbuffers###"); qglRenderbufferStorageEXT = (RenderbufferStorageEXT_t)R_GetProcAddressExt("glRenderbufferStorage###"); qglRenderbufferStorageMultisampleEXT = (RenderbufferStorageMultisampleEXT_t)R_GetProcAddressExt("glRenderbufferStorageMultisample###"); qglGetRenderbufferParameterivEXT = (GetRenderbufferParameterivEXT_t)R_GetProcAddressExt("glGetRenderbufferParameteriv###"); qglIsFramebufferEXT = (IsFramebufferEXT_t)R_GetProcAddressExt("glIsFramebuffer###"); qglBindFramebufferEXT = (BindFramebufferEXT_t)R_GetProcAddressExt("glBindFramebuffer###"); qglDeleteFramebuffersEXT = (DeleteFramebuffersEXT_t)R_GetProcAddressExt("glDeleteFramebuffers###"); qglGenFramebuffersEXT = (GenFramebuffersEXT_t)R_GetProcAddressExt("glGenFramebuffers###"); qglCheckFramebufferStatusEXT = (CheckFramebufferStatusEXT_t)R_GetProcAddressExt("glCheckFramebufferStatus###"); qglFramebufferTexture1DEXT = (FramebufferTexture1DEXT_t)R_GetProcAddressExt("glFramebufferTexture1D###"); qglFramebufferTexture2DEXT = (FramebufferTexture2DEXT_t)R_GetProcAddressExt("glFramebufferTexture2D###"); qglFramebufferTexture3DEXT = (FramebufferTexture3DEXT_t)R_GetProcAddressExt("glFramebufferTexture3D###"); qglFramebufferRenderbufferEXT = (FramebufferRenderbufferEXT_t)R_GetProcAddressExt("glFramebufferRenderbuffer###"); qglGetFramebufferAttachmentParameterivEXT = (GetFramebufferAttachmentParameterivEXT_t)R_GetProcAddressExt("glGetFramebufferAttachmentParameteriv###"); qglGenerateMipmapEXT = (GenerateMipmapEXT_t)R_GetProcAddressExt("glGenerateMipmap###"); qglDrawBuffers = (DrawBuffers_t)R_GetProcAddress("glDrawBuffers"); qglBlitFramebuffer = (BlitFramebuffer_t)R_GetProcAddress("glBlitFramebuffer"); if (qglDeleteRenderbuffersEXT && qglDeleteFramebuffersEXT && qglGenFramebuffersEXT && qglBindFramebufferEXT && qglFramebufferTexture2DEXT && qglBindRenderbufferEXT && qglRenderbufferStorageEXT && qglCheckFramebufferStatusEXT) { glGetIntegerv(GL_MAX_DRAW_BUFFERS, &r_config.maxDrawBuffers); glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &r_config.maxColorAttachments); glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &r_config.maxRenderbufferSize); r_config.frameBufferObject = true; Com_Printf("using GL_ARB_framebuffer_object\n"); Com_Printf("max draw buffers: %i\n", r_config.maxDrawBuffers); Com_Printf("max render buffer size: %i\n", r_config.maxRenderbufferSize); Com_Printf("max color attachments: %i\n", r_config.maxColorAttachments); } else { Com_Printf("skipping GL_ARB_framebuffer_object - not every needed extension is supported\n"); } if (r_config.maxDrawBuffers > 1 && R_CheckExtension("GL_###_draw_buffers")) { Com_Printf("using GL_ARB_draw_buffers\n"); r_config.drawBuffers = true; } else { r_config.drawBuffers = false; } } else { Com_Printf("Framebuffer objects unsupported by OpenGL implementation.\n"); } r_programs = Cvar_Get("r_programs", "1", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "GLSL shaders level: 0 - disabled, 1 - low, 2 - medium, 3 - high"); r_programs->modified = false; Cvar_SetCheckFunction("r_programs", R_CvarPrograms); r_glsl_version = Cvar_Get("r_glsl_version", "1.10", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "GLSL Version"); Cvar_SetCheckFunction("r_glsl_version", R_CvarGLSLVersionCheck); r_postprocess = Cvar_Get("r_postprocess", "1", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "Activate postprocessing shader effects"); Cvar_SetCheckFunction("r_postprocess", R_CvarPostProcess); /* reset gl error state */ R_CheckError(); glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, &r_config.maxVertexTextureImageUnits); Com_Printf("max supported vertex texture units: %i\n", r_config.maxVertexTextureImageUnits); glGetIntegerv(GL_MAX_LIGHTS, &r_config.maxLights); Com_Printf("max supported lights: %i\n", r_config.maxLights); r_dynamic_lights = Cvar_Get("r_dynamic_lights", "1", CVAR_ARCHIVE | CVAR_R_PROGRAMS, "Sets max number of GL lightsources to use in shaders"); Cvar_SetCheckFunction("r_dynamic_lights", R_CvarCheckDynamicLights); glGetIntegerv(GL_MAX_TEXTURE_UNITS, &r_config.maxTextureUnits); Com_Printf("max texture units: %i\n", r_config.maxTextureUnits); if (r_config.maxTextureUnits < 2) Com_Error(ERR_FATAL, "You need at least 2 texture units to run " GAME_TITLE); glGetIntegerv(GL_MAX_TEXTURE_COORDS, &r_config.maxTextureCoords); Com_Printf("max texture coords: %i\n", r_config.maxTextureCoords); r_config.maxTextureCoords = std::max(r_config.maxTextureUnits, r_config.maxTextureCoords); glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &r_config.maxVertexAttribs); Com_Printf("max vertex attributes: %i\n", r_config.maxVertexAttribs); glGetIntegerv(GL_MAX_VARYING_FLOATS, &tmpInteger); Com_Printf("max varying floats: %i\n", tmpInteger); glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &tmpInteger); Com_Printf("max fragment uniform components: %i\n", tmpInteger); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &tmpInteger); Com_Printf("max vertex uniform components: %i\n", tmpInteger); /* reset gl error state */ R_CheckError(); /* check max texture size */ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &r_config.maxTextureSize); /* stubbed or broken drivers may have reported 0 */ if (r_config.maxTextureSize <= 0) r_config.maxTextureSize = 256; if ((err = glGetError()) != GL_NO_ERROR) { Com_Printf("max texture size: cannot detect - using %i! (%s)\n", r_config.maxTextureSize, R_TranslateError(err)); Cvar_SetValue("r_maxtexres", r_config.maxTextureSize); } else { Com_Printf("max texture size: detected %d\n", r_config.maxTextureSize); if (r_maxtexres->integer > r_config.maxTextureSize) { Com_Printf("...downgrading from %i\n", r_maxtexres->integer); Cvar_SetValue("r_maxtexres", r_config.maxTextureSize); /* check for a minimum */ } else if (r_maxtexres->integer >= 128 && r_maxtexres->integer < r_config.maxTextureSize) { Com_Printf("...but using %i as requested\n", r_maxtexres->integer); r_config.maxTextureSize = r_maxtexres->integer; } } if (r_config.maxTextureSize > 4096 && R_ImageExists("pics/geoscape/%s/map_earth_season_00", "high")) { Q_strncpyz(r_config.lodDir, "high", sizeof(r_config.lodDir)); Com_Printf("Using high resolution globe textures as requested.\n"); } else if (r_config.maxTextureSize > 2048 && R_ImageExists("pics/geoscape/med/map_earth_season_00")) { if (r_config.maxTextureSize > 4096) { Com_Printf("Warning: high resolution globe textures requested, but could not be found; falling back to medium resolution globe textures.\n"); } else { Com_Printf("Using medium resolution globe textures as requested.\n"); } Q_strncpyz(r_config.lodDir, "med", sizeof(r_config.lodDir)); } else { if (r_config.maxTextureSize > 2048) { Com_Printf("Warning: medium resolution globe textures requested, but could not be found; falling back to low resolution globe textures.\n"); } else { Com_Printf("Using low resolution globe textures as requested.\n"); } Q_strncpyz(r_config.lodDir, "low", sizeof(r_config.lodDir)); } }
/** * @sa R_RenderFrame * @sa R_EndFrame */ void R_BeginFrame (void) { r_locals.frame++; /* avoid overflows, negatives and zero are reserved */ if (r_locals.frame > 0xffff) r_locals.frame = 1; if (Com_IsRenderModified()) { Com_Printf("Modified render related cvars\n"); if (Cvar_PendingCvars(CVAR_R_PROGRAMS)) R_RestartPrograms_f(); /* prevent reloading of some rendering cvars */ Cvar_ClearVars(CVAR_R_MASK); Com_SetRenderModified(false); } if (r_anisotropic->modified) { if (r_anisotropic->integer > r_config.maxAnisotropic) { Com_Printf("...max GL_EXT_texture_filter_anisotropic value is %i\n", r_config.maxAnisotropic); Cvar_SetValue("r_anisotropic", r_config.maxAnisotropic); } /*R_UpdateAnisotropy();*/ r_anisotropic->modified = false; } /* draw buffer stuff */ if (r_drawbuffer->modified) { r_drawbuffer->modified = false; if (Q_strcasecmp(r_drawbuffer->string, "GL_FRONT") == 0) glDrawBuffer(GL_FRONT); else glDrawBuffer(GL_BACK); R_CheckError(); } /* texturemode stuff */ /* Realtime set level of anisotropy filtering and change texture lod bias */ if (r_texturemode->modified) { R_TextureMode(r_texturemode->string); r_texturemode->modified = false; } if (r_texturealphamode->modified) { R_TextureAlphaMode(r_texturealphamode->string); r_texturealphamode->modified = false; } if (r_texturesolidmode->modified) { R_TextureSolidMode(r_texturesolidmode->string); r_texturesolidmode->modified = false; } /* threads */ if (r_threads->modified) { if (r_threads->integer) R_InitThreads(); else R_ShutdownThreads(); r_threads->modified = false; } R_Setup2D(); /* clear screen if desired */ R_Clear(); }