diff --git a/code/renderercommon/qgl.h b/code/renderercommon/qgl.h index 9dc1b8c..02045a4 100644 --- a/code/renderercommon/qgl.h +++ b/code/renderercommon/qgl.h @@ -721,6 +721,11 @@ extern void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); #define GL_DEPTH_CLAMP 0x864F #endif +#ifndef GL_ARB_seamless_cube_map +#define GL_ARB_seamless_cube_map +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#endif + #if defined(WIN32) // WGL_ARB_create_context #ifndef WGL_ARB_create_context diff --git a/code/renderergl2/glsl/lightall_fp.glsl b/code/renderergl2/glsl/lightall_fp.glsl index 0b455dd..02a2621 100644 --- a/code/renderergl2/glsl/lightall_fp.glsl +++ b/code/renderergl2/glsl/lightall_fp.glsl @@ -1,3 +1,7 @@ +#ifndef USE_SPECULARMAP +#define USE_TRIACE +#endif + uniform sampler2D u_DiffuseMap; #if defined(USE_LIGHTMAP) @@ -20,6 +24,10 @@ uniform sampler2D u_SpecularMap; uniform sampler2D u_ShadowMap; #endif +#if defined(USE_CUBEMAP) +uniform samplerCube u_CubeMap; +#endif + uniform vec3 u_ViewOrigin; #if defined(USE_TCGEN) @@ -157,28 +165,38 @@ vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL, if (gamma >= 0.0) #endif { - B *= max(max(NL, NE), EPSILON); + B = max(B * max(NL, NE), EPSILON); } - return diffuseAlbedo * (A + gamma / B); + return diffuseAlbedo * NL * (A + gamma / B); #else - return diffuseAlbedo; + return diffuseAlbedo * NL; #endif } -#if defined(USE_SPECULARMAP) -vec3 CalcSpecular(vec3 specularReflectance, float NH, float NL, float NE, float EH, float shininess) +float CalcFresnelBlend(float EH) +{ + float blend = 1.0 - EH; + float blend2 = blend * blend; + blend *= blend2 * blend2; + + return blend; +} + +vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float shininess) { #if defined(USE_BLINN) || defined(USE_TRIACE) || defined(USE_TORRANCE_SPARROW) float blinn = pow(NH, shininess); #endif #if defined(USE_BLINN) - return specularReflectance * blinn; + float scale = 0.5 * shininess + 1.0; + + return specular * scale * blinn; #endif #if defined(USE_COOK_TORRANCE) || defined (USE_TRIACE) || defined (USE_TORRANCE_SPARROW) - vec3 fresnel = specularReflectance + (vec3(1.0) - specularReflectance) * pow(1.0 - EH, 5); + vec3 fresnelSpec = mix(specular, vec3(1.0), CalcFresnelBlend(EH)); #endif #if defined(USE_COOK_TORRANCE) || defined(USE_TORRANCE_SPARROW) @@ -192,22 +210,21 @@ vec3 CalcSpecular(vec3 specularReflectance, float NH, float NL, float NE, float float m_NH_sq = m_sq * NH_sq; float beckmann = exp((NH_sq - 1.0) / max(m_NH_sq, EPSILON)) / max(4.0 * m_NH_sq * NH_sq, EPSILON); - return fresnel * geo * beckmann / max(NE, EPSILON); + return fresnelSpec * geo * beckmann / max(NE, EPSILON); #endif #if defined(USE_TRIACE) float scale = 0.1248582 * shininess + 0.2691817; - return fresnel * scale * blinn / max(max(NL, NE), EPSILON); + return fresnelSpec * scale * blinn * clamp(NL / max(NE, EPSILON), 0.0, 1.0); #endif #if defined(USE_TORRANCE_SPARROW) float scale = 0.125 * shininess + 1.0; - return fresnel * geo * scale * blinn / max(NE, EPSILON); + return fresnelSpec * geo * scale * blinn / max(NE, EPSILON); #endif } -#endif void main() { @@ -296,9 +313,9 @@ void main() } #endif - vec4 diffuseAlbedo = texture2D(u_DiffuseMap, texCoords); -#if defined(USE_LIGHT) && defined(USE_GAMMA2_TEXTURES) - diffuseAlbedo.rgb *= diffuseAlbedo.rgb; + vec4 diffuse = texture2D(u_DiffuseMap, texCoords); +#if defined(USE_LIGHT) && defined(USE_LINEAR_LIGHT) + diffuse.rgb *= diffuse.rgb; #endif #if defined(USE_LIGHT) && defined(USE_FAST_LIGHT) @@ -367,63 +384,73 @@ void main() float NL = clamp(dot(N, L), 0.0, 1.0); float NE = clamp(dot(N, E), 0.0, 1.0); - float maxReflectance = u_MaterialInfo.x; - float shininess = u_MaterialInfo.y; + float maxSpecular = u_MaterialInfo.x; + float maxSpecularPower = 2048.0; + float shininess, gloss; #if defined(USE_SPECULARMAP) - vec4 specularReflectance = texture2D(u_SpecularMap, texCoords); - specularReflectance.rgb *= maxReflectance; - shininess *= specularReflectance.a; - // adjust diffuse by specular reflectance, to maintain energy conservation - diffuseAlbedo.rgb *= vec3(1.0) - specularReflectance.rgb; + vec4 specular = texture2D(u_SpecularMap, texCoords); + gloss = specular.a; + #else + vec4 specular = vec4(1, 1, 1, 1); + maxSpecular = 0.04; + gloss = 0.5; #endif - gl_FragColor.rgb = lightColor * NL * CalcDiffuse(diffuseAlbedo.rgb, N, L, E, NE, NL, shininess); - gl_FragColor.rgb += ambientDiff * ambientColor * diffuseAlbedo.rgb; - #if defined(USE_PRIMARY_LIGHT) - vec3 L2 = var_PrimaryLightDirection; - float NL2 = clamp(dot(N, L2), 0.0, 1.0); - - #if defined(USE_SHADOWMAP) - gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * NL2 * CalcDiffuse(diffuseAlbedo.rgb, N, L2, E, NE, NL2, shininess); - #else - gl_FragColor.rgb += u_PrimaryLightColor * NL2 * CalcDiffuse(diffuseAlbedo.rgb, N, L2, E, NE, NL2, shininess); - #endif + shininess = pow(maxSpecularPower, gloss); + specular.rgb *= maxSpecular; + // adjust diffuse by specular reflectance, to maintain energy conservation + diffuse.rgb *= vec3(1.0) - specular.rgb; + + gl_FragColor.rgb = lightColor * CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess); + gl_FragColor.rgb += ambientDiff * ambientColor * diffuse.rgb; + + #if defined(USE_CUBEMAP) + gl_FragColor.rgb += texture(u_CubeMap, reflect(E, N), 8.0 - gloss * 8.0).rgb * mix(specular.rgb, vec3(1.0), CalcFresnelBlend(NE) / (4.0 - 3.0 * gloss)); #endif - - #if defined(USE_SPECULARMAP) + +#if 0 vec3 H = normalize(L + E); float EH = clamp(dot(E, H), 0.0, 1.0); float NH = clamp(dot(N, H), 0.0, 1.0); - gl_FragColor.rgb += lightColor * NL * CalcSpecular(specularReflectance.rgb, NH, NL, NE, EH, shininess); - - #if defined(r_normalAmbient) + gl_FragColor.rgb += lightColor * CalcSpecular(specular.rgb, NH, NL, NE, EH, shininess); + + #if defined(r_normalAmbient) vec3 ambientHalf = normalize(surfN + E); float ambientSpec = max(dot(ambientHalf, N) + 0.5, 0.0); ambientSpec *= ambientSpec * 0.44; - gl_FragColor.rgb += specularReflectance.rgb * ambientSpec * ambientColor; + gl_FragColor.rgb += specular.rgb * ambientSpec * ambientColor; + #endif +#endif + + #if defined(USE_PRIMARY_LIGHT) + vec3 L2 = var_PrimaryLightDirection; + float NL2 = clamp(dot(N, L2), 0.0, 1.0); + + #if defined(USE_SHADOWMAP) + gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * CalcDiffuse(diffuse.rgb, N, L2, E, NE, NL2, shininess); + #else + gl_FragColor.rgb += u_PrimaryLightColor * CalcDiffuse(diffuse.rgb, N, L2, E, NE, NL2, shininess); #endif - #if defined(USE_PRIMARY_LIGHT) vec3 H2 = normalize(L2 + E); float EH2 = clamp(dot(E, H2), 0.0, 1.0); float NH2 = clamp(dot(N, H2), 0.0, 1.0); - #if defined(USE_SHADOWMAP) - gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * NL2 * CalcSpecular(specularReflectance.rgb, NH2, NL2, NE, EH2, shininess); - #else - gl_FragColor.rgb += u_PrimaryLightColor * NL2 * CalcSpecular(specularReflectance.rgb, NH2, NL2, NE, EH2, shininess); - #endif + #if defined(USE_SHADOWMAP) + gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * CalcSpecular(specular.rgb, NH2, NL2, NE, EH2, shininess); + #else + gl_FragColor.rgb += u_PrimaryLightColor * CalcSpecular(specular.rgb, NH2, NL2, NE, EH2, shininess); #endif - #endif + #endif #else - gl_FragColor.rgb = diffuseAlbedo.rgb; + gl_FragColor.rgb = diffuse.rgb; #endif - gl_FragColor.a = diffuseAlbedo.a; + gl_FragColor.a = diffuse.a; gl_FragColor *= var_Color; } diff --git a/code/renderergl2/tr_animation.c b/code/renderergl2/tr_animation.c index c4c9deb..5751326 100644 --- a/code/renderergl2/tr_animation.c +++ b/code/renderergl2/tr_animation.c @@ -51,7 +51,7 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) { surface = (md4Surface_t *)( (byte *)lod + lod->ofsSurfaces ); for ( i = 0 ; i < lod->numSurfaces ; i++ ) { shader = R_GetShaderByHandle( surface->shaderIndex ); - R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse, qfalse ); + R_AddDrawSurf( (void *)surface, shader, 0 /*fogNum*/, qfalse, qfalse, 0 /*cubeMap*/ ); surface = (md4Surface_t *)( (byte *)surface + surface->ofsEnd ); } } @@ -419,7 +419,7 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse ); + R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse, qfalse, 0 ); } // projection shadows work fine with personal models @@ -428,11 +428,11 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { && (ent->e.renderfx & RF_SHADOW_PLANE ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse ); + R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse, qfalse, 0 ); } if (!personalModel) - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse ); + R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse, qfalse, 0 ); surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd ); } diff --git a/code/renderergl2/tr_backend.c b/code/renderergl2/tr_backend.c index de05f53..e8f9155 100644 --- a/code/renderergl2/tr_backend.c +++ b/code/renderergl2/tr_backend.c @@ -141,7 +141,11 @@ void GL_BindToTMU( image_t *image, int tmu ) if (image) image->frameUsed = tr.frameCount; glState.currenttextures[tmu] = texnum; - qglBindTexture( GL_TEXTURE_2D, texnum ); + + if (image->flags & IMGFLAG_CUBEMAP) + qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum ); + else + qglBindTexture( GL_TEXTURE_2D, texnum ); GL_SelectTexture( oldtmu ); } } @@ -496,6 +500,13 @@ void RB_BeginDrawingView (void) { else { FBO_Bind(backEnd.viewParms.targetFbo); + + // FIXME: hack for cubemap testing + if (backEnd.viewParms.targetFbo == tr.playerCubeFbo) + { + //qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0); + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]->texnum, 0); + } } } @@ -530,6 +541,13 @@ void RB_BeginDrawingView (void) { qglClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); } + // clear to black for cube maps + if (backEnd.viewParms.targetFbo == tr.playerCubeFbo) + { + clearBits |= GL_COLOR_BUFFER_BIT; + qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + } + qglClear( clearBits ); if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) @@ -581,6 +599,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { int entityNum, oldEntityNum; int dlighted, oldDlighted; int pshadowed, oldPshadowed; + int cubemapIndex, oldCubemapIndex; qboolean depthRange, oldDepthRange, isCrosshair, wasCrosshair; int i; drawSurf_t *drawSurf; @@ -606,6 +625,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { wasCrosshair = qfalse; oldDlighted = qfalse; oldPshadowed = qfalse; + oldCubemapIndex = -1; oldSort = -1; depth[0] = 0.f; @@ -614,7 +634,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { - if ( drawSurf->sort == oldSort ) { + if ( drawSurf->sort == oldSort && drawSurf->cubemapIndex == oldCubemapIndex) { if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) continue; @@ -624,22 +644,24 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { } oldSort = drawSurf->sort; R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); + cubemapIndex = drawSurf->cubemapIndex; // // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites - if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed + if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { if (oldShader != NULL) { RB_EndSurface(); } - RB_BeginSurface( shader, fogNum ); + RB_BeginSurface( shader, fogNum, cubemapIndex ); backEnd.pc.c_surfBatches++; oldShader = shader; oldFogNum = fogNum; oldDlighted = dlighted; oldPshadowed = pshadowed; + oldCubemapIndex = cubemapIndex; } if (backEnd.depthFill && shader && shader->sort != SS_OPAQUE) @@ -981,7 +1003,7 @@ const void *RB_StretchPic ( const void *data ) { RB_EndSurface(); } backEnd.currentEntity = &backEnd.entity2D; - RB_BeginSurface( shader, 0 ); + RB_BeginSurface( shader, 0, 0 ); } RB_CHECKOVERFLOW( 4, 6 ); @@ -1311,8 +1333,15 @@ const void *RB_DrawSurfs( const void *data ) { RB_RenderFlares(); } - //if (glRefConfig.framebufferObject) - //FBO_Bind(NULL); + if (glRefConfig.framebufferObject && backEnd.viewParms.targetFbo == tr.playerCubeFbo) + { + FBO_Bind(NULL); + GL_SelectTexture(TB_CUBEMAP); + //GL_BindToTMU(tr.playerCubeMap, TB_CUBEMAP); + GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP); + qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); + GL_SelectTexture(0); + } return (const void *)(cmd + 1); } @@ -1650,7 +1679,10 @@ const void *RB_PostProcess(const void *data) srcBox[2] = backEnd.viewParms.viewportWidth * tr.screenSsaoImage->width / (float)glConfig.vidWidth; srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight; - FBO_BlitFromTexture(tr.screenSsaoImage, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); + srcBox[1] = tr.screenSsaoImage->height - srcBox[1]; + srcBox[3] = -srcBox[3]; + + FBO_Blit(tr.screenSsaoFbo, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); } srcBox[0] = backEnd.viewParms.viewportX; @@ -1678,7 +1710,7 @@ const void *RB_PostProcess(const void *data) color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); color[3] = 1.0f; - FBO_Blit(srcFbo, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, color, 0); + FBO_Blit(srcFbo, srcBox, NULL, tr.screenScratchFbo, dstBox, NULL, color, 0); } } @@ -1717,6 +1749,39 @@ const void *RB_PostProcess(const void *data) FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); } +#if 0 + if (1) + { + vec4i_t dstBox; + int i; + vec_t shortest = (float)WORLD_SIZE * (float)WORLD_SIZE; + int shortestNum = 0; + //ri.Printf(PRINT_ALL, "%d %d %d\n", (int)backEnd.viewParms.or.origin[0], (int)backEnd.viewParms.or.origin[1], (int)backEnd.viewParms.or.origin[2]); + + for (i = 0; i < tr.numCubemaps; i++) + { + vec3_t diff; + vec_t length; + + VectorSubtract(backEnd.viewParms.or.origin, tr.cubemapOrigins[i], diff); + + length = DotProduct(diff, diff); + + //ri.Printf(PRINT_ALL, "%d: %d %d %d - %d %d %d = (%d)\n", i, (int)tr.cubemapOrigins[i][0], (int)tr.cubemapOrigins[i][1], (int)tr.cubemapOrigins[i][2], (int)diff[0], (int)diff[1], (int)diff[2], (int)length); + + if (shortest > length) + { + shortest = length; + shortestNum = i; + } + } + + VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256); + //FBO_BlitFromTexture(tr.playerCubeMap, NULL, NULL, tr.screenScratchFbo, dstBox, &tr.testcubeShader, NULL, 0); + FBO_BlitFromTexture(tr.cubemaps[shortestNum], NULL, NULL, tr.screenScratchFbo, dstBox, &tr.testcubeShader, NULL, 0); + } +#endif + backEnd.framePostProcessed = qtrue; return (const void *)(cmd + 1); diff --git a/code/renderergl2/tr_bsp.c b/code/renderergl2/tr_bsp.c index 05b933e..eaaf5e1 100644 --- a/code/renderergl2/tr_bsp.c +++ b/code/renderergl2/tr_bsp.c @@ -1805,6 +1805,14 @@ static int BSPSurfaceCompare(const void *a, const void *b) else if(aa->fogIndex > bb->fogIndex) return 1; + // by cubemapIndex + if(aa->cubemapIndex < bb->cubemapIndex) + return -1; + + else if(aa->cubemapIndex > bb->cubemapIndex) + return 1; + + return 0; } @@ -2866,6 +2874,7 @@ void R_MergeLeafSurfaces(void) msurface_t *surf1; shader_t *shader1; int fogIndex1; + int cubemapIndex1; int surfNum1; surfNum1 = *(s_worldData.marksurfaces + leaf->firstmarksurface + j); @@ -2890,6 +2899,7 @@ void R_MergeLeafSurfaces(void) continue; fogIndex1 = surf1->fogIndex; + cubemapIndex1 = surf1->cubemapIndex; s_worldData.surfacesViewCount[surfNum1] = surfNum1; @@ -2898,6 +2908,7 @@ void R_MergeLeafSurfaces(void) msurface_t *surf2; shader_t *shader2; int fogIndex2; + int cubemapIndex2; int surfNum2; surfNum2 = *(s_worldData.marksurfaces + leaf->firstmarksurface + k); @@ -2920,6 +2931,11 @@ void R_MergeLeafSurfaces(void) if (fogIndex1 != fogIndex2) continue; + cubemapIndex2 = surf2->cubemapIndex; + + if (cubemapIndex1 != cubemapIndex2) + continue; + s_worldData.surfacesViewCount[surfNum2] = surfNum1; } } @@ -3153,6 +3169,7 @@ void R_MergeLeafSurfaces(void) vboSurf->shader = surf1->shader; vboSurf->fogIndex = surf1->fogIndex; + vboSurf->cubemapIndex = surf1->cubemapIndex; VectorCopy(bounds[0], vboSurf->bounds[0]); VectorCopy(bounds[1], vboSurf->bounds[1]); @@ -3163,6 +3180,7 @@ void R_MergeLeafSurfaces(void) mergedSurf->cullinfo.type = CULLINFO_BOX; mergedSurf->data = (surfaceType_t *)vboSurf; mergedSurf->fogIndex = surf1->fogIndex; + mergedSurf->cubemapIndex = surf1->cubemapIndex; mergedSurf->shader = surf1->shader; // redirect view surfaces to this surf @@ -3539,6 +3557,138 @@ void RE_LoadWorldMap( const char *name ) { ri.Free(primaryLightGrid); } + // load cubemaps + { + char filename[MAX_QPATH]; + char *cubemapText = NULL; + int size = 0; + int i; + world_t *w; + + w = &s_worldData; + + // look for cubemaps + if (1) + { + Com_sprintf( filename, sizeof( filename ), "maps/%s/cubemaps.txt", w->baseName); + //ri.Printf(PRINT_ALL, "looking for %s\n", filename); + + size = ri.FS_ReadFile(filename, (void **)&cubemapText); + } + + if (size && cubemapText) + { + char *data = cubemapText; + char *token; + + //ri.Printf(PRINT_ALL, "found!\n"); + + token = COM_ParseExt(&data, qfalse); + tr.numCubemaps = atoi(token); + + //ri.Printf(PRINT_ALL, "cubemaps %d\n", tr.numCubemaps); + tr.cubemapOrigins = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemapOrigins), h_low); + tr.cubemaps = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemaps), h_low); + + SkipRestOfLine(&data); + + for (i = 0; i < tr.numCubemaps; i++) + { + int j; + + for (j = 0; j < 3; j++) + { + token = COM_ParseExt(&data, qfalse); + + if (!token) + break; + + tr.cubemapOrigins[i][j] = atof(token); + } + + SkipRestOfLine(&data); + ri.Printf(PRINT_ALL, "cubemap at %f %f %f\n", tr.cubemapOrigins[i][0], tr.cubemapOrigins[i][1], tr.cubemapOrigins[i][2]); + } + + for (i = 0; i < w->numsurfaces; i++) + { + msurface_t *surf = &w->surfaces[i]; + vec3_t surfOrigin; + vec_t shortest = (float)WORLD_SIZE * (float)WORLD_SIZE; + int shortestNum = -1; + int j; + // note: not necessarily two sided, just convenient to use in a check later + cullType_t ct = CT_TWO_SIDED; + + if (surf->cullinfo.type & CULLINFO_SPHERE) + { + VectorCopy(surf->cullinfo.localOrigin, surfOrigin); + } + else if (surf->cullinfo.type & CULLINFO_BOX) + { + surfOrigin[0] = (surf->cullinfo.bounds[0][0] + surf->cullinfo.bounds[1][0]) * 0.5f; + surfOrigin[1] = (surf->cullinfo.bounds[0][1] + surf->cullinfo.bounds[1][1]) * 0.5f; + surfOrigin[2] = (surf->cullinfo.bounds[0][2] + surf->cullinfo.bounds[1][2]) * 0.5f; + } + else + { + //ri.Printf(PRINT_ALL, "surface %d has no cubemap\n", i); + continue; + } + + if (surf->cullinfo.type & CULLINFO_PLANE) + { + ct = surf->shader->cullType; + } + else + { + ct = CT_TWO_SIDED; + } + + for (j = 0; j < tr.numCubemaps; j++) + { + vec3_t diff; + vec_t length; + + // FIXME: this is from R_CullSurface, should consolidate code + if (0) //(ct != CT_TWO_SIDED) + { + vec_t d = DotProduct (tr.cubemapOrigins[j], surf->cullinfo.plane.normal); + + // don't cull exactly on the plane, because there are levels of rounding + // through the BSP, ICD, and hardware that may cause pixel gaps if an + // epsilon isn't allowed here + if ( ct == CT_FRONT_SIDED ) { + if ( d < surf->cullinfo.plane.dist - 8 ) { + continue; + } + } else { + if ( d > surf->cullinfo.plane.dist + 8 ) { + continue; + } + } + } + + VectorSubtract(surfOrigin, tr.cubemapOrigins[j], diff); + + length = DotProduct(diff, diff); + + if (shortest > length) + { + shortest = length; + shortestNum = j; + } + } + + //ri.Printf(PRINT_ALL, "surface %d has cubemap %d\n", i, shortestNum); + surf->cubemapIndex = shortestNum + 1; + } + } + + if (cubemapText) + ri.FS_FreeFile(cubemapText); + } + // create static VBOS from the world R_CreateWorldVBO(); if (r_mergeLeafSurfaces->integer) @@ -3555,5 +3705,22 @@ void RE_LoadWorldMap( const char *name ) { R_BindNullVBO(); R_BindNullIBO(); + // Render all cubemaps + { + int i; + + for (i = 0; i < tr.numCubemaps; i++) + { + tr.cubemaps[i] = R_CreateImage(va("*cubeMap%d", i), NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, GL_RGBA8); + } + + for (i = 0; i < tr.numCubemaps; i++) + { + RE_ClearScene(); + R_RenderCubemap(i, qfalse); + R_IssuePendingRenderCommands(); + } + } + ri.FS_FreeFile( buffer.v ); } diff --git a/code/renderergl2/tr_extensions.c b/code/renderergl2/tr_extensions.c index 0b70d48..95fb552 100644 --- a/code/renderergl2/tr_extensions.c +++ b/code/renderergl2/tr_extensions.c @@ -664,4 +664,17 @@ void GLimp_InitExtraExtensions() { ri.Printf(PRINT_ALL, result[2], extension); } + + // GL_ARB_seamless_cube_map + extension = "GL_ARB_seamless_cube_map"; + glRefConfig.seamlessCubeMap = qfalse; + if( GLimp_HaveExtension( extension ) ) + { + glRefConfig.seamlessCubeMap = qtrue; + ri.Printf(PRINT_ALL, result[1], extension); + } + else + { + ri.Printf(PRINT_ALL, result[2], extension); + } } diff --git a/code/renderergl2/tr_fbo.c b/code/renderergl2/tr_fbo.c index fee11d5..aca2c27 100644 --- a/code/renderergl2/tr_fbo.c +++ b/code/renderergl2/tr_fbo.c @@ -579,6 +579,19 @@ void FBO_Init(void) R_CheckFBO(tr.screenSsaoFbo); } + { + tr.playerCubeFbo = FBO_Create("_playerCubeFbo", tr.playerCubeMap->width, tr.playerCubeMap->height); + FBO_Bind(tr.playerCubeFbo); + + //FBO_AttachTextureImage(tr.playerCubeMap, 0); + R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.playerCubeMap->texnum, 0); + glState.currentFBO->colorImage[0] = tr.playerCubeMap; + + FBO_CreateBuffer(tr.playerCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); + + R_CheckFBO(tr.playerCubeFbo); + } + GL_CheckErrors(); FBO_Bind(NULL); @@ -783,7 +796,10 @@ void FBO_Blit(FBO_t *src, vec4i_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, vec4 vec4i_t srcBox; if (!src) + { + ri.Printf(PRINT_WARNING, "Tried to blit from a NULL FBO!\n"); return; + } // framebuffers are 0 bottom, Y up. if (inSrcBox) diff --git a/code/renderergl2/tr_flares.c b/code/renderergl2/tr_flares.c index 5bcefa2..bc016c1 100644 --- a/code/renderergl2/tr_flares.c +++ b/code/renderergl2/tr_flares.c @@ -370,7 +370,7 @@ void RB_RenderFlare( flare_t *f ) { iColor[1] = color[1] * fogFactors[1]; iColor[2] = color[2] * fogFactors[2]; - RB_BeginSurface( tr.flareShader, f->fogNum ); + RB_BeginSurface( tr.flareShader, f->fogNum, 0 ); // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; diff --git a/code/renderergl2/tr_glsl.c b/code/renderergl2/tr_glsl.c index d8b0743..3e39f24 100644 --- a/code/renderergl2/tr_glsl.c +++ b/code/renderergl2/tr_glsl.c @@ -71,6 +71,7 @@ static uniformInfo_t uniformsInfo[] = { "u_TextureMap", GLSL_INT }, { "u_LevelsMap", GLSL_INT }, + { "u_CubeMap", GLSL_INT }, { "u_ScreenImageMap", GLSL_INT }, { "u_ScreenDepthMap", GLSL_INT }, @@ -1020,6 +1021,8 @@ void GLSL_InitGPUShaders(void) { if (i & LIGHTDEF_USE_SHADOWMAP) continue; + if (i & LIGHTDEF_USE_CUBEMAP) + continue; } attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL; @@ -1112,6 +1115,9 @@ void GLSL_InitGPUShaders(void) if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer) Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n"); + if ((i & LIGHTDEF_USE_CUBEMAP)) + Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n"); + if (i & LIGHTDEF_USE_SHADOWMAP) { Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); @@ -1155,6 +1161,7 @@ void GLSL_InitGPUShaders(void) GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DELUXEMAP, TB_DELUXEMAP); GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP); GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP); + GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP, TB_CUBEMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.lightallShader[i]); @@ -1361,6 +1368,26 @@ void GLSL_InitGPUShaders(void) numEtcShaders++; } +#if 0 + attribs = ATTR_POSITION | ATTR_TEXCOORD; + extradefines[0] = '\0'; + + if (!GLSL_InitGPUShader(&tr.testcubeShader, "testcube", attribs, qtrue, extradefines, qtrue, NULL, NULL)) + { + ri.Error(ERR_FATAL, "Could not load testcube shader!"); + } + + GLSL_InitUniforms(&tr.testcubeShader); + + qglUseProgramObjectARB(tr.testcubeShader.program); + GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP); + qglUseProgramObjectARB(0); + + GLSL_FinishGPUShader(&tr.testcubeShader); + + numEtcShaders++; +#endif + endTime = ri.Milliseconds(); diff --git a/code/renderergl2/tr_image.c b/code/renderergl2/tr_image.c index c9ca6ce..d172760 100644 --- a/code/renderergl2/tr_image.c +++ b/code/renderergl2/tr_image.c @@ -2282,8 +2282,17 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (image->flags & IMGFLAG_MIPMAP) + { + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + else + { + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic); @@ -2926,6 +2935,8 @@ void R_CreateBuiltinImages( void ) { { tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); } + + tr.playerCubeMap = R_CreateImage("*playerCubeMap", NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, GL_RGBA8); } } diff --git a/code/renderergl2/tr_init.c b/code/renderergl2/tr_init.c index d533024..798fb38 100644 --- a/code/renderergl2/tr_init.c +++ b/code/renderergl2/tr_init.c @@ -955,6 +955,9 @@ void GL_SetDefaultState( void ) qglDrawBuffer( GL_BACK ); qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); + + if (glRefConfig.seamlessCubeMap) + qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); } /* diff --git a/code/renderergl2/tr_light.c b/code/renderergl2/tr_light.c index a34d9ba..8a29353 100644 --- a/code/renderergl2/tr_light.c +++ b/code/renderergl2/tr_light.c @@ -413,7 +413,7 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { R_LightForPoint ================= */ -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) +int R_LightForPoint( const vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) { trRefEntity_t ent; diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h index 144b16e..a5a35a6 100644 --- a/code/renderergl2/tr_local.h +++ b/code/renderergl2/tr_local.h @@ -59,6 +59,7 @@ typedef unsigned int glIndex_t; #define MAX_CALC_PSHADOWS 64 #define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces #define PSHADOW_MAP_SIZE 512 +#define CUBE_MAP_SIZE 64 #define USE_VERT_TANGENT_SPACE @@ -368,7 +369,8 @@ enum TB_SHADOWMAP2 = 3, TB_SPECULARMAP = 4, TB_SHADOWMAP = 5, - NUM_TEXTURE_BUNDLES = 6 + TB_CUBEMAP = 6, + NUM_TEXTURE_BUNDLES = 7 }; typedef enum @@ -703,8 +705,9 @@ enum LIGHTDEF_USE_DELUXEMAP = 0x0040, LIGHTDEF_USE_PARALLAXMAP = 0x0080, LIGHTDEF_USE_SHADOWMAP = 0x0100, - LIGHTDEF_ALL = 0x01FF, - LIGHTDEF_COUNT = 0x0200 + LIGHTDEF_USE_CUBEMAP = 0x0200, + LIGHTDEF_ALL = 0x03FF, + LIGHTDEF_COUNT = 0x0400 }; enum @@ -728,6 +731,7 @@ typedef enum UNIFORM_TEXTUREMAP, UNIFORM_LEVELSMAP, + UNIFORM_CUBEMAP, UNIFORM_SCREENIMAGEMAP, UNIFORM_SCREENDEPTHMAP, @@ -896,12 +900,14 @@ typedef struct { typedef enum { VPF_NONE = 0x00, - VPF_SHADOWMAP = 0x01, - VPF_DEPTHSHADOW = 0x02, - VPF_DEPTHCLAMP = 0x04, - VPF_ORTHOGRAPHIC = 0x08, - VPF_USESUNLIGHT = 0x10, - VPF_FARPLANEFRUSTUM = 0x20 + VPF_NOVIEWMODEL = 0x01, + VPF_SHADOWMAP = 0x02, + VPF_DEPTHSHADOW = 0x04, + VPF_DEPTHCLAMP = 0x08, + VPF_ORTHOGRAPHIC = 0x10, + VPF_USESUNLIGHT = 0x20, + VPF_FARPLANEFRUSTUM = 0x40, + VPF_NOCUBEMAPS = 0x80 } viewParmFlags_t; typedef struct { @@ -916,6 +922,8 @@ typedef struct { cplane_t portalPlane; // clip anything behind this if mirroring int viewportX, viewportY, viewportWidth, viewportHeight; FBO_t *targetFbo; + int targetFboLayer; + int targetFboCubemapIndex; float fovX, fovY; float projectionMatrix[16]; cplane_t frustum[5]; @@ -958,7 +966,8 @@ typedef enum { } surfaceType_t; typedef struct drawSurf_s { - unsigned sort; // bit combination for fast compares + unsigned int sort; // bit combination for fast compares + int cubemapIndex; surfaceType_t *surface; // any of surface*_t } drawSurf_t; @@ -1170,6 +1179,7 @@ typedef struct srfVBOMesh_s struct shader_s *shader; // FIXME move this to somewhere else int fogIndex; + int cubemapIndex; // dynamic lighting information int dlightBits; @@ -1271,6 +1281,7 @@ typedef struct msurface_s { //int viewCount; // if == tr.viewCount, already added struct shader_s *shader; int fogIndex; + int cubemapIndex; cullinfo_t cullinfo; surfaceType_t *data; // any of srf*_t @@ -1603,6 +1614,7 @@ typedef struct { qboolean texture_srgb; qboolean depthClamp; + qboolean seamlessCubeMap; } glRefConfig_t; @@ -1715,6 +1727,7 @@ typedef struct { image_t *screenShadowImage; image_t *screenSsaoImage; image_t *hdrDepthImage; + image_t *playerCubeMap; image_t *textureDepthImage; @@ -1732,6 +1745,7 @@ typedef struct { FBO_t *screenShadowFbo; FBO_t *screenSsaoFbo; FBO_t *hdrDepthFbo; + FBO_t *playerCubeFbo; shader_t *defaultShader; shader_t *shadowShader; @@ -1749,6 +1763,10 @@ typedef struct { int fatLightmapSize; int fatLightmapStep; + int numCubemaps; + vec3_t *cubemapOrigins; + image_t **cubemaps; + trRefEntity_t *currentEntity; trRefEntity_t worldEntity; // point currentEntity at this when rendering world int currentEntityNum; @@ -1772,6 +1790,7 @@ typedef struct { shaderProgram_t shadowmaskShader; shaderProgram_t ssaoShader; shaderProgram_t depthBlurShader[2]; + //shaderProgram_t testcubeShader; // ----------------------------------------- @@ -2008,6 +2027,7 @@ void R_RenderView( viewParms_t *parms ); void R_RenderDlightCubemaps(const refdef_t *fd); void R_RenderPshadowMaps(const refdef_t *fd); void R_RenderSunShadowMaps(const refdef_t *fd, int level); +void R_RenderCubemap( int cubemapIndex, qboolean subscene ); void R_AddMD3Surfaces( trRefEntity_t *e ); void R_AddNullModelSurfaces( trRefEntity_t *e ); @@ -2021,7 +2041,7 @@ void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, int *fogNum, int *dlightMap, int *pshadowMap ); void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap, int pshadowMap ); + int fogIndex, int dlightMap, int pshadowMap, int cubemap ); void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2); @@ -2198,6 +2218,7 @@ typedef struct shaderCommands_s shader_t *shader; float shaderTime; int fogNum; + int cubemapIndex; int dlightBits; // or together of all vertexDlightBits int pshadowBits; @@ -2223,7 +2244,7 @@ typedef struct shaderCommands_s extern shaderCommands_t tess; -void RB_BeginSurface(shader_t *shader, int fogNum ); +void RB_BeginSurface(shader_t *shader, int fogNum, int cubemapIndex ); void RB_EndSurface(void); void RB_CheckOverflow( int verts, int indexes ); #define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);} @@ -2281,7 +2302,7 @@ LIGHTS void R_DlightBmodel( bmodel_t *bmodel ); void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ); void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or ); -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); +int R_LightForPoint( const vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *world ); @@ -2405,7 +2426,9 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ); void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ); void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); +void RE_BeginScene( const refdef_t *fd ); void RE_RenderScene( const refdef_t *fd ); +void RE_EndScene( void ); /* ============================================================= diff --git a/code/renderergl2/tr_main.c b/code/renderergl2/tr_main.c index b67c5fa..f10906d 100644 --- a/code/renderergl2/tr_main.c +++ b/code/renderergl2/tr_main.c @@ -1607,7 +1607,7 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 R_RotateForViewer(); R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - RB_BeginSurface( shader, fogNum ); + RB_BeginSurface( shader, fogNum, drawSurf->cubemapIndex); rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); assert( tess.numVertexes < 128 ); @@ -1844,7 +1844,7 @@ R_AddDrawSurf ================= */ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap, int pshadowMap ) { + int fogIndex, int dlightMap, int pshadowMap, int cubemap ) { int index; // instead of checking for overflow, we just mask the index @@ -1855,6 +1855,7 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap; + tr.refdef.drawSurfs[index].cubemapIndex = cubemap; tr.refdef.drawSurfs[index].surface = surface; tr.refdef.numDrawSurfs++; } @@ -1958,8 +1959,7 @@ static void R_AddEntitySurface (int entityNum) // we don't want the hacked weapon position showing in // mirrors, because the true body position will already be drawn // - if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.isPortal - || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW))) ) { + if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.flags & VPF_NOVIEWMODEL)) { return; } @@ -1979,7 +1979,7 @@ static void R_AddEntitySurface (int entityNum) return; } shader = R_GetShaderByHandle( ent->e.customShader ); - R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0 ); + R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0, 0 /*cubeMap*/ ); break; case RT_MODEL: @@ -1988,7 +1988,7 @@ static void R_AddEntitySurface (int entityNum) tr.currentModel = R_GetModelByHandle( ent->e.hModel ); if (!tr.currentModel) { - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0 ); + R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 /*cubeMap*/ ); } else { switch ( tr.currentModel->type ) { case MOD_MESH: @@ -2010,7 +2010,7 @@ static void R_AddEntitySurface (int entityNum) if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { break; } - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0 ); + R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 ); break; default: ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); @@ -2186,7 +2186,7 @@ void R_RenderDlightCubemaps(const refdef_t *fd) shadowParms.fovX = 90; shadowParms.fovY = 90; - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW; + shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; shadowParms.zFar = tr.refdef.dlights[i].radius; VectorCopy( tr.refdef.dlights[i].origin, shadowParms.or.origin ); @@ -2490,7 +2490,7 @@ void R_RenderPshadowMaps(const refdef_t *fd) if (glRefConfig.framebufferObject) shadowParms.targetFbo = tr.pshadowFbos[i]; - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW; + shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; shadowParms.zFar = shadow->lightRadius; VectorCopy(shadow->lightOrigin, shadowParms.or.origin); @@ -2835,7 +2835,7 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level) if (glRefConfig.framebufferObject) shadowParms.targetFbo = tr.sunShadowFbo[level]; - shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC; + shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC | VPF_NOVIEWMODEL; shadowParms.zFar = lightviewBounds[1][0]; VectorCopy(lightOrigin, shadowParms.or.origin); @@ -2874,3 +2874,121 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level) Matrix16Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]); } } + +void R_RenderCubemap( int cubemapIndex, qboolean subscene ) +{ + refdef_t *fd, refdef; + viewParms_t cubeviewParms; + float oldColorScale = tr.refdef.colorScale; + int j; + + if (!subscene) + { + fd = &refdef; + memset( &refdef, 0, sizeof( refdef ) ); + + refdef.rdflags = 0; + + VectorCopy(tr.cubemapOrigins[cubemapIndex], refdef.vieworg); + AxisClear( refdef.viewaxis ); + + refdef.fov_x = 90; + refdef.fov_y = 90; + + refdef.x = 0; + refdef.y = 0; + refdef.width = tr.playerCubeFbo->width; + refdef.height = tr.playerCubeFbo->height; + + refdef.time = 0; + + RE_BeginScene(fd); + + // FIXME: sun shadows aren't rendered correctly in cubemaps + if(0) //(glRefConfig.framebufferObject && (r_forceSun->integer || tr.sunShadows)) + { + R_RenderSunShadowMaps(fd, 0); + R_RenderSunShadowMaps(fd, 1); + R_RenderSunShadowMaps(fd, 2); + } + } + + { + vec3_t ambient, directed, lightDir; + R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir); + tr.refdef.colorScale = 766.0f / (directed[0] + directed[1] + directed[2] + 1.0f); + } + + Com_Memset( &cubeviewParms, 0, sizeof( cubeviewParms ) ); + + cubeviewParms.viewportX = 0; + cubeviewParms.viewportY = 0; + cubeviewParms.viewportWidth = tr.playerCubeFbo->width; + cubeviewParms.viewportHeight = tr.playerCubeFbo->height; + cubeviewParms.isPortal = qfalse; + cubeviewParms.isMirror = qtrue; + cubeviewParms.flags = VPF_NOVIEWMODEL | VPF_NOCUBEMAPS; + + cubeviewParms.fovX = 90; + cubeviewParms.fovY = 90; + + VectorCopy( tr.refdef.vieworg, cubeviewParms.or.origin ); + VectorCopy( tr.refdef.vieworg, cubeviewParms.pvsOrigin ); + + for (j = 0; j < 6; j++) + { + cubeviewParms.targetFbo = tr.playerCubeFbo; + cubeviewParms.targetFboLayer = j; + cubeviewParms.targetFboCubemapIndex = cubemapIndex; + switch(j) + { + case 0: + // -X + VectorSet( cubeviewParms.or.axis[0], -1, 0, 0); + VectorSet( cubeviewParms.or.axis[1], 0, 0, -1); + VectorSet( cubeviewParms.or.axis[2], 0, 1, 0); + break; + case 1: + // +X + VectorSet( cubeviewParms.or.axis[0], 1, 0, 0); + VectorSet( cubeviewParms.or.axis[1], 0, 0, 1); + VectorSet( cubeviewParms.or.axis[2], 0, 1, 0); + break; + case 2: + // -Y + VectorSet( cubeviewParms.or.axis[0], 0, -1, 0); + VectorSet( cubeviewParms.or.axis[1], 1, 0, 0); + VectorSet( cubeviewParms.or.axis[2], 0, 0, -1); + break; + case 3: + // +Y + VectorSet( cubeviewParms.or.axis[0], 0, 1, 0); + VectorSet( cubeviewParms.or.axis[1], 1, 0, 0); + VectorSet( cubeviewParms.or.axis[2], 0, 0, 1); + break; + case 4: + // -Z + VectorSet( cubeviewParms.or.axis[0], 0, 0, -1); + VectorSet( cubeviewParms.or.axis[1], 1, 0, 0); + VectorSet( cubeviewParms.or.axis[2], 0, 1, 0); + break; + case 5: + // +Z + VectorSet( cubeviewParms.or.axis[0], 0, 0, 1); + VectorSet( cubeviewParms.or.axis[1], -1, 0, 0); + VectorSet( cubeviewParms.or.axis[2], 0, 1, 0); + break; + } + + R_RenderView(&cubeviewParms); + } + + if (subscene) + { + tr.refdef.colorScale = oldColorScale; + } + else + { + RE_EndScene(); + } +} \ No newline at end of file diff --git a/code/renderergl2/tr_mesh.c b/code/renderergl2/tr_mesh.c index 28c2e5f..31ba2ce 100644 --- a/code/renderergl2/tr_mesh.c +++ b/code/renderergl2/tr_mesh.c @@ -387,7 +387,7 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { { srfVBOMDVMesh_t *vboSurface = &model->vboSurfaces[i]; - R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse ); + R_AddDrawSurf((void *)vboSurface, shader, fogNum, qfalse, qfalse, 0 /*cubeMap*/ ); } surface++; diff --git a/code/renderergl2/tr_model_iqm.c b/code/renderergl2/tr_model_iqm.c index 30b8ff0..6e4d4db 100644 --- a/code/renderergl2/tr_model_iqm.c +++ b/code/renderergl2/tr_model_iqm.c @@ -866,7 +866,7 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { && fogNum == 0 && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0 ); + R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0, 0 ); } // projection shadows work fine with personal models @@ -874,11 +874,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { && fogNum == 0 && (ent->e.renderfx & RF_SHADOW_PLANE ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0 ); + R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0 ); } if( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0 ); + R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, 0 /*cubeMap*/ ); } surface++; diff --git a/code/renderergl2/tr_scene.c b/code/renderergl2/tr_scene.c index 7e77418..ef5c6f1 100644 --- a/code/renderergl2/tr_scene.c +++ b/code/renderergl2/tr_scene.c @@ -99,7 +99,7 @@ void R_AddPolygonSurfaces( void ) { for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) { sh = R_GetShaderByHandle( poly->hShader ); - R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse ); + R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse, 0 /*cubeMap*/ ); } } @@ -283,36 +283,9 @@ void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, flo RE_AddDynamicLightToScene( org, intensity, r, g, b, qtrue ); } -/* -@@@@@@@@@@@@@@@@@@@@@ -RE_RenderScene - -Draw a 3D view into a part of the window, then return -to 2D drawing. - -Rendering a scene may require multiple views to be rendered -to handle mirrors, -@@@@@@@@@@@@@@@@@@@@@ -*/ -void RE_RenderScene( const refdef_t *fd ) { - viewParms_t parms; - int startTime; - - if ( !tr.registered ) { - return; - } - GLimp_LogComment( "====== RE_RenderScene =====\n" ); - - if ( r_norefresh->integer ) { - return; - } - - startTime = ri.Milliseconds(); - - if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { - ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); - } +void RE_BeginScene(const refdef_t *fd) +{ Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); tr.refdef.x = fd->x; @@ -466,6 +439,49 @@ void RE_RenderScene( const refdef_t *fd ) { // each scene / view. tr.frameSceneNum++; tr.sceneCount++; +} + + +void RE_EndScene() +{ + // the next scene rendered in this frame will tack on after this one + r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; + r_firstSceneEntity = r_numentities; + r_firstSceneDlight = r_numdlights; + r_firstScenePoly = r_numpolys; +} + +/* +@@@@@@@@@@@@@@@@@@@@@ +RE_RenderScene + +Draw a 3D view into a part of the window, then return +to 2D drawing. + +Rendering a scene may require multiple views to be rendered +to handle mirrors, +@@@@@@@@@@@@@@@@@@@@@ +*/ +void RE_RenderScene( const refdef_t *fd ) { + viewParms_t parms; + int startTime; + + if ( !tr.registered ) { + return; + } + GLimp_LogComment( "====== RE_RenderScene =====\n" ); + + if ( r_norefresh->integer ) { + return; + } + + startTime = ri.Milliseconds(); + + if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { + ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); + } + + RE_BeginScene(fd); // SmileTheory: playing with shadow mapping if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2) @@ -487,6 +503,18 @@ void RE_RenderScene( const refdef_t *fd ) { R_RenderSunShadowMaps(fd, 2); } + // playing with cube maps + // this is where dynamic cubemaps would be rendered + if (0) //(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL )) + { + int i; + + for (i = 0; i < tr.numCubemaps; i++) + { + R_RenderCubemap(i, qtrue); + } + } + // setup view parms for the initial view // // set up viewport @@ -522,11 +550,7 @@ void RE_RenderScene( const refdef_t *fd ) { if(!( fd->rdflags & RDF_NOWORLDMODEL )) R_AddPostProcessCmd(); - // the next scene rendered in this frame will tack on after this one - r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; - r_firstSceneEntity = r_numentities; - r_firstSceneDlight = r_numdlights; - r_firstScenePoly = r_numpolys; + RE_EndScene(); tr.frontEndMsec += ri.Milliseconds() - startTime; } diff --git a/code/renderergl2/tr_shade.c b/code/renderergl2/tr_shade.c index 633b3f4..8a74459 100644 --- a/code/renderergl2/tr_shade.c +++ b/code/renderergl2/tr_shade.c @@ -186,7 +186,7 @@ because a surface may be forced to perform a RB_End due to overflow. ============== */ -void RB_BeginSurface( shader_t *shader, int fogNum ) { +void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) { shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader; @@ -196,6 +196,7 @@ void RB_BeginSurface( shader_t *shader, int fogNum ) { tess.multiDrawPrimitives = 0; tess.shader = state; tess.fogNum = fogNum; + tess.cubemapIndex = cubemapIndex; tess.dlightBits = 0; // will be OR'd in by surface functions tess.pshadowBits = 0; // will be OR'd in by surface functions tess.xstages = state->stages; @@ -1133,6 +1134,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) index |= LIGHTDEF_USE_SHADOWMAP; } + if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && (index & LIGHTDEF_LIGHTTYPE_MASK) && input->cubemapIndex) + { + index |= LIGHTDEF_USE_CUBEMAP; + } + if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP) { index = LIGHTDEF_USE_LIGHTMAP; @@ -1177,39 +1183,10 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { vec4_t baseColor; vec4_t vertColor; - qboolean tint = qtrue; - int stage2; ComputeShaderColors(pStage, baseColor, vertColor); - for ( stage2 = stage + 1; stage2 < MAX_SHADER_STAGES; stage2++ ) - { - shaderStage_t *pStage2 = input->xstages[stage2]; - unsigned int srcBlendBits; - //unsigned int dstBlendBits; - - if ( !pStage2 ) - { - break; - } - - srcBlendBits = pStage2->stateBits & GLS_SRCBLEND_BITS; - //dstBlendBits = pStage2->stateBits & GLS_DSTBLEND_BITS; - - if (srcBlendBits == GLS_SRCBLEND_DST_COLOR) - { - tint = qfalse; - break; - } - } - - if (!((tr.sunShadows || r_forceSun->integer) && tess.shader->sort <= SS_OPAQUE - && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) && tess.xstages[0]->glslShaderGroup == tr.lightallShader)) - { - tint = qfalse; - } - - if (tint) + if ((backEnd.refdef.colorScale != 1.0f) && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) { // use VectorScale to only scale first three values, not alpha VectorScale(baseColor, backEnd.refdef.colorScale, baseColor); @@ -1374,6 +1351,12 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) } // + // testing cube map + // + if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex) + GL_BindToTMU( tr.cubemaps[input->cubemapIndex - 1], TB_CUBEMAP); + + // // draw // if (input->multiDrawPrimitives) diff --git a/code/renderergl2/tr_sky.c b/code/renderergl2/tr_sky.c index f1e5249..7fd4b3a 100644 --- a/code/renderergl2/tr_sky.c +++ b/code/renderergl2/tr_sky.c @@ -449,7 +449,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max color[0] = color[1] = - color[2] = tr.identityLight; + color[2] = tr.identityLight * backEnd.refdef.colorScale; color[3] = 1.0f; GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color); @@ -826,7 +826,7 @@ void RB_DrawSun( float scale, shader_t *shader ) { // farthest depth range qglDepthRange( 1.0, 1.0 ); - RB_BeginSurface( shader, 0 ); + RB_BeginSurface( shader, 0, 0 ); RB_AddQuadStamp(origin, vec1, vec2, colorWhite); diff --git a/code/renderergl2/tr_surface.c b/code/renderergl2/tr_surface.c index 427d153..06072a8 100644 --- a/code/renderergl2/tr_surface.c +++ b/code/renderergl2/tr_surface.c @@ -63,7 +63,7 @@ void RB_CheckOverflow( int verts, int indexes ) { ri.Error(ERR_DROP, "RB_CheckOverflow: indices > MAX (%d > %d)", indexes, SHADER_MAX_INDEXES ); } - RB_BeginSurface(tess.shader, tess.fogNum ); + RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex ); } void RB_CheckVBOandIBO(VBO_t *vbo, IBO_t *ibo) @@ -71,7 +71,7 @@ void RB_CheckVBOandIBO(VBO_t *vbo, IBO_t *ibo) if (!(vbo == glState.currentVBO && ibo == glState.currentIBO) || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES) { RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum); + RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); R_BindVBO(vbo); R_BindIBO(ibo); @@ -1370,7 +1370,7 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) { // if we don't have enough space for at least one strip, flush the buffer if ( vrows < 2 || irows < 1 ) { RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum ); + RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex ); } else { break; } @@ -1593,7 +1593,7 @@ void RB_SurfaceVBOMDVMesh(srfVBOMDVMesh_t * surface) //RB_CheckVBOandIBO(surface->vbo, surface->ibo); RB_EndSurface(); - RB_BeginSurface(tess.shader, tess.fogNum); + RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); R_BindVBO(surface->vbo); R_BindIBO(surface->ibo); diff --git a/code/renderergl2/tr_world.c b/code/renderergl2/tr_world.c index e67be16..0ee4ad2 100644 --- a/code/renderergl2/tr_world.c +++ b/code/renderergl2/tr_world.c @@ -337,7 +337,7 @@ static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits pshadowBits = ( pshadowBits != 0 ); } - R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits ); + R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits, surf->cubemapIndex ); } /*