/* TODO: - Firstly save each iteration of our water, so we can keep track of colour etc. - Recalc colour for different dynamic moving lights. */ void Warp_DrawWaterPoly(glpoly_t *p) { VideoObject_t *voWaterPoly; vec3_t vWave,vLightColour; float *v; int i; voWaterPoly = malloc(p->numverts*sizeof(VideoObject_t)); if(!voWaterPoly) { Sys_Error("Failed to allocate water poly!\n"); return; } v = p->verts[0]; for(i = 0; i < p->numverts; i++,v += VERTEXSIZE) { voWaterPoly[i].vTextureCoord[0][0] = WARPCALC(v[3],v[4]); voWaterPoly[i].vTextureCoord[0][1] = WARPCALC(v[4],v[3]); voWaterPoly[i].vColour[3] = Math_Clamp(0, r_wateralpha.value, 1.0f); Math_VectorCopy(v,vWave); // Shitty lit water, use dynamic light points in the future... { MathVector_t mvLightColour; // Use vWave position BEFORE we move it, otherwise the water will flicker. mvLightColour = Light_GetSample(vWave); Math_MVToVector(mvLightColour,vLightColour); Math_VectorScale(vLightColour,1.0f/200.0f,vLightColour); Math_VectorDivide(vLightColour,0.2f,vLightColour); } Math_VectorCopy(vLightColour,voWaterPoly[i].vColour); // [20/1/2013] Added in subtle water bobbing, based on this code http://www.quake-1.com/docs/quakesrc.org/26.html ~hogsy vWave[2] = v[2]+ 2.0f*(float)sin(v[0]*0.025f+cl.time)*(float)sin(v[2]*0.05f+cl.time)+ 2.0f*(float)sin(v[1]*0.025f+cl.time*2.0f)*(float)sin(v[2]*0.05f+cl.time); Math_VectorCopy(vWave,voWaterPoly[i].vVertex); } Video_DrawObject(voWaterPoly,VIDEO_PRIMITIVE_TRIANGLE_FAN,p->numverts); free(voWaterPoly); }
/* Typically called before an object is drawn. */ void Material_Draw(Material_t *Material, int Skin, VideoVertex_t *ObjectVertex, VideoPrimitive_t ObjectPrimitive, unsigned int ObjectSize, bool ispost) { if (r_drawflat_cheatsafe || !Material) return; if ((Material->override_wireframe && (r_showtris.iValue != 1) || !Material->override_wireframe) && (r_lightmap_cheatsafe || r_showtris.bValue)) { if (!ispost) { // Select the first TMU. Video_SelectTexture(0); // Set it as white. Video_SetTexture(g_mGlobalColour->msSkin[MATERIAL_COLOUR_WHITE].mtTexture->gMap); } return; } MaterialSkin_t *msCurrentSkin; if (Material->iFlags & MATERIAL_FLAG_ANIMATED) msCurrentSkin = Material_GetAnimatedSkin(Material); else msCurrentSkin = Material_GetSkin(Material, Skin); if (!msCurrentSkin) Sys_Error("Failed to get valid skin! (%s)\n", Material->cName); // Handle any generic blending. if ((msCurrentSkin->uiFlags & MATERIAL_FLAG_BLEND) || (Material->fAlpha < 1)) { if (!ispost) { vlDepthMask(false); VideoLayer_Enable(VIDEO_BLEND); if (msCurrentSkin->uiFlags & MATERIAL_FLAG_ADDITIVE) // Additive blending isn't done by default. VideoLayer_BlendFunc(VIDEO_BLEND_ADDITIVE); } else { vlDepthMask(true); VideoLayer_Disable(VIDEO_BLEND); if (msCurrentSkin->uiFlags & MATERIAL_FLAG_ADDITIVE) // Return blend mode to its default. VideoLayer_BlendFunc(VIDEO_BLEND_DEFAULT); } } unsigned int i, uiCurrentUnit; for (i = 0, uiCurrentUnit = 0; i < msCurrentSkin->uiTextures; i++, uiCurrentUnit++) { #ifdef VIDEO_LIGHTMAP_HACKS // Skip the lightmap, since it's manually handled. if (uiCurrentUnit == VIDEO_TEXTURE_LIGHT) uiCurrentUnit++; #endif // Attempt to select the unit (if it's already selected, then it'll just return). Video_SelectTexture(uiCurrentUnit); if (!ispost) { // Enable it. VideoLayer_Enable(VIDEO_TEXTURE_2D); // Bind it. Video_SetTexture(msCurrentSkin->mtTexture[i].gMap); // Allow us to manipulate the texture. if (msCurrentSkin->mtTexture[i].matrixmod) { glMatrixMode(GL_TEXTURE); glLoadIdentity(); if ((msCurrentSkin->mtTexture[i].vScroll[0] > 0) || (msCurrentSkin->mtTexture[i].vScroll[0] < 0) || (msCurrentSkin->mtTexture[i].vScroll[1] > 0) || (msCurrentSkin->mtTexture[i].vScroll[1] < 0)) glTranslatef( msCurrentSkin->mtTexture[i].vScroll[0] * cl.time, msCurrentSkin->mtTexture[i].vScroll[1] * cl.time, 0); if ((msCurrentSkin->mtTexture[i].fRotate > 0) || (msCurrentSkin->mtTexture[i].fRotate < 0)) glRotatef(msCurrentSkin->mtTexture[i].fRotate*cl.time, 0, 0, 1.0f); glMatrixMode(GL_MODELVIEW); } } switch (msCurrentSkin->mtTexture[i].mttType) { case MATERIAL_TEXTURE_LIGHTMAP: case MATERIAL_TEXTURE_DIFFUSE: if (!ispost) { #if 0 // TODO: Material shader assignments!!!! VideoShader_SetVariablei(iDiffuseUniform, Video.current_textureunit); #endif if (uiCurrentUnit > 0) { VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_DECAL); // Check if we've been given a video object to use... if (ObjectVertex) { unsigned int j; // Go through the whole object. for (j = 0; j < ObjectSize; j++) { // Copy over original texture coords. Video_ObjectTexture(&ObjectVertex[j], uiCurrentUnit, // Use base texture coordinates as a reference. ObjectVertex[j].mvST[0][0], ObjectVertex[j].mvST[0][1]); } } } else VideoLayer_SetTextureEnvironmentMode(msCurrentSkin->mtTexture[i].EnvironmentMode); if ((msCurrentSkin->mtTexture[i].uiFlags & MATERIAL_FLAG_ALPHA) || (msCurrentSkin->uiFlags & MATERIAL_FLAG_ALPHA)) VideoLayer_Enable(VIDEO_ALPHA_TEST); } else { if ((msCurrentSkin->mtTexture[i].uiFlags & MATERIAL_FLAG_ALPHA) || (msCurrentSkin->uiFlags & MATERIAL_FLAG_ALPHA)) { VideoLayer_Disable(VIDEO_ALPHA_TEST); if ((msCurrentSkin->uiFlags & MATERIAL_FLAG_ALPHATRICK) && (cv_video_alphatrick.bValue && (ObjectSize > 0))) { vlDepthMask(false); VideoLayer_Enable(VIDEO_BLEND); // Draw the object again (don't bother passing material). Video_DrawObject(ObjectVertex, ObjectPrimitive, ObjectSize, NULL, 0); VideoLayer_Disable(VIDEO_BLEND); vlDepthMask(true); } } VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_MODULATE); } break; case MATERIAL_TEXTURE_DETAIL: if (!ispost) { if (!cv_video_drawdetail.bValue) { Video_DisableCapabilities(VIDEO_TEXTURE_2D); break; } VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 2); // Check if we've been given a video object to use... if (ObjectVertex) { unsigned int j; // Go through the whole object. for (j = 0; j < ObjectSize; j++) { // Copy over original texture coords. Video_ObjectTexture(&ObjectVertex[j], uiCurrentUnit, // Use base texture coordinates as a reference. ObjectVertex[j].mvST[0][0] * cv_video_detailscale.value, ObjectVertex[j].mvST[0][1] * cv_video_detailscale.value); // TODO: Modify them to the appropriate scale. } } } else { VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1); } break; case MATERIAL_TEXTURE_FULLBRIGHT: if (!ispost) { if (!gl_fullbrights.bValue) { Video_DisableCapabilities(VIDEO_TEXTURE_2D); break; } VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_ADD); if (uiCurrentUnit > 0) { // Check if we've been given a video object to use... if (ObjectVertex) { unsigned int j; // Go through the whole object. for (j = 0; j < ObjectSize; j++) { // Copy over original texture coords. Video_ObjectTexture(&ObjectVertex[j], uiCurrentUnit, // Use base texture coordinates as a reference. ObjectVertex[j].mvST[0][0], ObjectVertex[j].mvST[0][1]); } } } } else VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_MODULATE); break; case MATERIAL_TEXTURE_SPHERE: if (!ispost) { VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_COMBINE); Video_GenerateSphereCoordinates(); VideoLayer_Enable(VIDEO_TEXTURE_GEN_S | VIDEO_TEXTURE_GEN_T); } else { VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_MODULATE); VideoLayer_Disable(VIDEO_TEXTURE_GEN_S | VIDEO_TEXTURE_GEN_T); } break; default: Sys_Error("Invalid texture type for material! (%s) (%i)\n", Material->cPath, msCurrentSkin->mtTexture[i].mttType); } if (ispost) { // Reset any manipulation within the matrix. if (msCurrentSkin->mtTexture[i].matrixmod) { glMatrixMode(GL_TEXTURE); glLoadIdentity(); glTranslatef(0, 0, 0); glRotatef(0, 0, 0, 0); glMatrixMode(GL_MODELVIEW); } // Disable the texture. VideoLayer_Disable(VIDEO_TEXTURE_2D); } } }