void FMD3Model::RenderFrame(FTexture * skin, int frameno, int cm, int translation) { if (frameno>=numFrames) return; MD3Frame * frame = &frames[frameno]; // I can't confirm correctness of this because no model I have tested uses this information // glMatrixMode(GL_MODELVIEW); // glTranslatef(frame->origin[0], frame->origin[1], frame->origin[2]); for(int i=0;i<numSurfaces;i++) { MD3Surface * surf = &surfaces[i]; // [BB] In case no skin is specified via MODELDEF, check if the MD3 has a skin for the current surface. // Note: Each surface may have a different skin. FTexture *surfaceSkin = skin; if (!surfaceSkin) { if (surf->numSkins==0) return; surfaceSkin = surf->skins[0]; if (!surfaceSkin) return; } FMaterial * tex = FMaterial::ValidateTexture(surfaceSkin); tex->Bind(cm, 0, translation); RenderTriangles(surf, surf->vertices + frameno * surf->numVertices); } }
void FMD3Model::RenderFrame(FTexture * skin, int frameno, int cm, Matrix3x4 *modeltoworld, int translation) { if (frameno>=numFrames) return; MD3Frame * frame = &frames[frameno]; // I can't confirm correctness of this because no model I have tested uses this information // gl.MatrixMode(GL_MODELVIEW); // gl.Translatef(frame->origin[0], frame->origin[1], frame->origin[2]); for(int i=0;i<numSurfaces;i++) { MD3Surface * surf = &surfaces[i]; if (!skin) { if (surf->numSkins==0) return; skin = surf->skins[0]; if (!skin) return; } FMaterial * tex = FMaterial::ValidateTexture(skin); tex->Bind(cm, 0, translation); RenderTriangles(surf, surf->vertices + frameno * surf->numVertices, modeltoworld); } }
FVelocityDrawingPolicy::FVelocityDrawingPolicy( const FVertexFactory* InVertexFactory, const FMaterialRenderProxy* InMaterialRenderProxy, const FMaterial& InMaterialResource, ERHIFeatureLevel::Type InFeatureLevel ) : FMeshDrawingPolicy(InVertexFactory,InMaterialRenderProxy,InMaterialResource) { const FMaterialShaderMap* MaterialShaderIndex = InMaterialResource.GetRenderingThreadShaderMap(); const FMeshMaterialShaderMap* MeshShaderIndex = MaterialShaderIndex->GetMeshShaderMap(InVertexFactory->GetType()); HullShader = NULL; DomainShader = NULL; const EMaterialTessellationMode MaterialTessellationMode = InMaterialResource.GetTessellationMode(); if (RHISupportsTessellation(GShaderPlatformForFeatureLevel[InFeatureLevel]) && InVertexFactory->GetType()->SupportsTessellationShaders() && MaterialTessellationMode != MTM_NoTessellation) { bool HasHullShader = MeshShaderIndex->HasShader(&FVelocityHS::StaticType); bool HasDomainShader = MeshShaderIndex->HasShader(&FVelocityDS::StaticType); HullShader = HasHullShader ? MeshShaderIndex->GetShader<FVelocityHS>() : NULL; DomainShader = HasDomainShader ? MeshShaderIndex->GetShader<FVelocityDS>() : NULL; } bool HasVertexShader = MeshShaderIndex->HasShader(&FVelocityVS::StaticType); VertexShader = HasVertexShader ? MeshShaderIndex->GetShader<FVelocityVS>() : NULL; bool HasPixelShader = MeshShaderIndex->HasShader(&FVelocityPS::StaticType); PixelShader = HasPixelShader ? MeshShaderIndex->GetShader<FVelocityPS>() : NULL; }
void FGLRenderer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, angle_t rotation, FDynamicColormap *colormap, int lightlevel) { if (npoints < 3) { // This is no polygon. return; } FMaterial *gltexture = FMaterial::ValidateTexture(texture); if (gltexture == NULL) { return; } FColormap cm; cm = colormap; lightlevel = gl_CalcLightLevel(lightlevel, 0, true); PalEntry pe = gl_CalcLightColor(lightlevel, cm.LightColor, cm.blendfactor, true); glColor3ub(pe.r, pe.g, pe.b); gltexture->Bind(cm.colormap); int i; float rot = float(rotation * M_PI / float(1u << 31)); bool dorotate = rot != 0; float cosrot = cos(rot); float sinrot = sin(rot); //float yoffs = GatheringWipeScreen ? 0 : LBOffset; float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); if (gltexture->tex->bHasCanvas) { vscale = 0 - vscale; } float ox = float(originx); float oy = float(originy); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); for (i = 0; i < npoints; ++i) { float u = points[i].X - 0.5f - ox; float v = points[i].Y - 0.5f - oy; if (dorotate) { float t = u; u = t * cosrot - v * sinrot; v = v * cosrot + t * sinrot; } glTexCoord2f(u * uscale, v * vscale); glVertex3f(points[i].X, points[i].Y /* + yoffs */, 0); } glEnd(); }
void FGLInterface::PrecacheTexture(FTexture *tex, int cache) { if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) { FMaterial * gltex = FMaterial::ValidateTexture(tex, false); if (gltex) gltex->Precache(); } }
FTransientDecalRenderData(FDeferredDecalProxy* InDecalProxy) : DecalProxy(InDecalProxy) { MaterialProxy = InDecalProxy->DecalMaterial->GetRenderProxy(InDecalProxy->bOwnerSelected); MaterialResource = MaterialProxy->GetMaterial(GRHIFeatureLevel); bHasNormal = MaterialResource->HasNormalConnected(); DecalBlendMode = ComputeFinalDecalBlendMode((EDecalBlendMode)MaterialResource->GetDecalBlendMode(), bHasNormal); check(MaterialProxy && MaterialResource); }
unsigned char *FGLRenderer::GetTextureBuffer(FTexture *tex, int &w, int &h) { FMaterial * gltex = FMaterial::ValidateTexture(tex); if (gltex) { return gltex->CreateTexBuffer(CM_DEFAULT, 0, w, h); } return NULL; }
class FMesh* FPrimitiveBuilder::CreateMesh(class FTexture* Texture, const glm::vec4& Colour, bool bUseIndexBuffer) { FMesh* Mesh = new FMesh(bUseIndexBuffer); FMaterial* Material = new FMaterial(Texture); Material->SetDiffuse(Colour); // TODO: Might need to fix this or add more stuff. check it later ProceduralModel->Meshes.push_back(Mesh); ProceduralModel->Materials.push_back(Material); Mesh->SetMaterial(Material); return Mesh; }
VulkanDescriptorSet *VkHardwareTexture::GetDescriptorSet(const FMaterialState &state) { FMaterial *mat = state.mMaterial; FTexture *tex = state.mMaterial->tex; int clampmode = state.mClampMode; int translation = state.mTranslation; if (tex->UseType == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; if (tex->isHardwareCanvas()) clampmode = CLAMP_CAMTEX; else if ((tex->isWarped() || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; // Textures that are already scaled in the texture lump will not get replaced by hires textures. int flags = state.mMaterial->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled() && clampmode <= CLAMP_XY) ? CTF_CheckHires : 0; if (tex->isHardwareCanvas()) static_cast<FCanvasTexture*>(tex)->NeedUpdate(); for (auto &set : mDescriptorSets) { if (set.descriptor && set.clampmode == clampmode && set.flags == flags) return set.descriptor.get(); } int numLayers = mat->GetLayers(); auto fb = GetVulkanFrameBuffer(); auto descriptor = fb->GetRenderPassManager()->AllocateTextureDescriptorSet(numLayers); descriptor->SetDebugName("VkHardwareTexture.mDescriptorSets"); VulkanSampler *sampler = fb->GetSamplerManager()->Get(clampmode); WriteDescriptors update; update.addCombinedImageSampler(descriptor.get(), 0, GetImage(tex, translation, flags)->View.get(), sampler, mImage.Layout); for (int i = 1; i < numLayers; i++) { FTexture *layer; auto systex = static_cast<VkHardwareTexture*>(mat->GetLayer(i, 0, &layer)); update.addCombinedImageSampler(descriptor.get(), i, systex->GetImage(layer, 0, mat->isExpanded() ? CTF_Expand : 0)->View.get(), sampler, systex->mImage.Layout); } update.updateSets(fb->device); mDescriptorSets.emplace_back(clampmode, flags, std::move(descriptor)); return mDescriptorSets.back().descriptor.get(); }
FDepthDrawingPolicy::FDepthDrawingPolicy( const FVertexFactory* InVertexFactory, const FMaterialRenderProxy* InMaterialRenderProxy, const FMaterial& InMaterialResource, bool bIsTwoSided, ERHIFeatureLevel::Type InFeatureLevel ): FMeshDrawingPolicy(InVertexFactory,InMaterialRenderProxy,InMaterialResource,false,/*bInTwoSidedOverride=*/ bIsTwoSided) { // The primitive needs to be rendered with the material's pixel and vertex shaders if it is masked bNeedsPixelShader = false; if (InMaterialResource.IsMasked()) { bNeedsPixelShader = true; PixelShader = InMaterialResource.GetShader<FDepthOnlyPS>(InVertexFactory->GetType()); } else { PixelShader = NULL; } const EMaterialTessellationMode TessellationMode = InMaterialResource.GetTessellationMode(); VertexShader = NULL; HullShader = NULL; DomainShader = NULL; if (RHISupportsTessellation(GShaderPlatformForFeatureLevel[InFeatureLevel]) && InVertexFactory->GetType()->SupportsTessellationShaders() && TessellationMode != MTM_NoTessellation) { VertexShader = InMaterialResource.GetShader<TDepthOnlyVS<false> >(VertexFactory->GetType()); HullShader = InMaterialResource.GetShader<FDepthOnlyHS>(VertexFactory->GetType()); DomainShader = InMaterialResource.GetShader<FDepthOnlyDS>(VertexFactory->GetType()); } else { VertexShader = InMaterialResource.GetShader<TDepthOnlyVS<false> >(InVertexFactory->GetType()); } }
void FMD3Model::RenderFrameInterpolated(FTexture * skin, int frameno, int frameno2, double inter, int cm, int translation) { if (frameno>=numFrames || frameno2>=numFrames) return; for(int i=0;i<numSurfaces;i++) { MD3Surface * surf = &surfaces[i]; // [BB] In case no skin is specified via MODELDEF, check if the MD3 has a skin for the current surface. // Note: Each surface may have a different skin. FTexture *surfaceSkin = skin; if (!surfaceSkin) { if (surf->numSkins==0) return; surfaceSkin = surf->skins[0]; if (!surfaceSkin) return; } FMaterial * tex = FMaterial::ValidateTexture(surfaceSkin); tex->Bind(cm, 0, translation); MD3Vertex* verticesInterpolated = new MD3Vertex[surfaces[i].numVertices]; MD3Vertex* vertices1 = surf->vertices + frameno * surf->numVertices; MD3Vertex* vertices2 = surf->vertices + frameno2 * surf->numVertices; // [BB] Calculate the interpolated vertices by linear interpolation. for( int k = 0; k < surf->numVertices; k++ ) { verticesInterpolated[k].x = (1-inter)*vertices1[k].x+ (inter)*vertices2[k].x; verticesInterpolated[k].y = (1-inter)*vertices1[k].y+ (inter)*vertices2[k].y; verticesInterpolated[k].z = (1-inter)*vertices1[k].z+ (inter)*vertices2[k].z; // [BB] Apparently RenderTriangles doesn't use nx, ny, nz, so don't interpolate them. } RenderTriangles(surf, verticesInterpolated); delete[] verticesInterpolated; } }
void FMD3Model::RenderFrameInterpolated(FTexture * skin, int frameno, int frameno2, double inter, int cm, Matrix3x4 *modeltoworld, int translation) { if (frameno>=numFrames || frameno2>=numFrames) return; for(int i=0;i<numSurfaces;i++) { MD3Surface * surf = &surfaces[i]; if (!skin) { if (surf->numSkins==0) return; skin = surf->skins[0]; if (!skin) return; } FMaterial * tex = FMaterial::ValidateTexture(skin); tex->Bind(cm, 0, translation); MD3Vertex* verticesInterpolated = new MD3Vertex[surfaces[i].numVertices]; MD3Vertex* vertices1 = surf->vertices + frameno * surf->numVertices; MD3Vertex* vertices2 = surf->vertices + frameno2 * surf->numVertices; // [BB] Calculate the interpolated vertices by linear interpolation. for( int k = 0; k < surf->numVertices; k++ ) { verticesInterpolated[k].x = (1-inter)*vertices1[k].x+ (inter)*vertices2[k].x; verticesInterpolated[k].y = (1-inter)*vertices1[k].y+ (inter)*vertices2[k].y; verticesInterpolated[k].z = (1-inter)*vertices1[k].z+ (inter)*vertices2[k].z; // [BB] Apparently RenderTriangles doesn't use nx, ny, nz, so don't interpolate them. } RenderTriangles(surf, verticesInterpolated, modeltoworld); delete[] verticesInterpolated; } }
void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) { // This doesn't need to clear the fake flat cache. It can be shared between camera textures and the main view of a scene. FMaterial * gltex = FMaterial::ValidateTexture(tex, false); int width = gltex->TextureWidth(); int height = gltex->TextureHeight(); StartOffscreen(); BindToFrameBuffer(gltex); IntRect bounds; bounds.left = bounds.top = 0; bounds.width = FHardwareTexture::GetTexDimension(gltex->GetWidth()); bounds.height = FHardwareTexture::GetTexDimension(gltex->GetHeight()); FRenderViewpoint texvp; RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false); EndOffscreen(); tex->SetUpdated(true); static_cast<OpenGLFrameBuffer*>(screen)->camtexcount++; }
void FGLInterface::RenderTextureView (FCanvasTexture *tex, AActor *Viewpoint, int FOV) { FMaterial * gltex = FMaterial::ValidateTexture(tex, false); int width = gltex->TextureWidth(); int height = gltex->TextureHeight(); gl_fixedcolormap=CM_DEFAULT; gl_RenderState.SetFixedColormap(CM_DEFAULT); if (gl.legacyMode) { // In legacy mode, fail if the requested texture is too large. if (gltex->GetWidth() > screen->GetWidth() || gltex->GetHeight() > screen->GetHeight()) return; glFlush(); } else { GLRenderer->StartOffscreen(); gltex->BindToFrameBuffer(); } GL_IRECT bounds; bounds.left=bounds.top=0; bounds.width=FHardwareTexture::GetTexDimension(gltex->GetWidth()); bounds.height=FHardwareTexture::GetTexDimension(gltex->GetHeight()); GLRenderer->RenderViewpoint(Viewpoint, &bounds, FOV, (float)width/height, (float)width/height, false, false); if (gl.legacyMode) { glFlush(); gl_RenderState.SetMaterial(gltex, 0, 0, -1, false); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bounds.width, bounds.height); } else { GLRenderer->EndOffscreen(); } tex->SetUpdated(); camtexcount++; }
//========================================================================== // // Draw the plane segment into the gap // //========================================================================== void FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) { GLSectorPlane plane; int lightlevel; FColormap Colormap; FMaterial * gltexture; plane.GetFromSector(sec, ceiling); gltexture=FMaterial::ValidateTexture(plane.texture, true); if (!gltexture) return; if (gl_fixedcolormap) { Colormap.GetFixedColormap(); lightlevel=255; } else { Colormap=sec->ColorMap; if (gltexture->tex->isFullbright()) { Colormap.LightColor.r = Colormap.LightColor.g = Colormap.LightColor.b = 0xff; lightlevel=255; } else lightlevel=abs(ceiling? sec->GetCeilingLight() : sec->GetFloorLight()); } int rel = getExtraLight(); gl_SetColor(lightlevel, rel, &Colormap, 1.0f); gl_SetFog(lightlevel, rel, &Colormap, false); gltexture->Bind(Colormap.colormap); float fviewx = FIXED2FLOAT(viewx); float fviewy = FIXED2FLOAT(viewy); float fviewz = FIXED2FLOAT(viewz); gl_RenderState.Apply(); bool pushed = gl_SetPlaneTextureRotation(&plane, gltexture); glBegin(GL_TRIANGLE_FAN); float prj_fac1 = (planez-fviewz)/(ws->z1-fviewz); float prj_fac2 = (planez-fviewz)/(ws->z2-fviewz); float px1 = fviewx + prj_fac1 * (ws->x1-fviewx); float py1 = fviewy + prj_fac1 * (ws->y1-fviewy); float px2 = fviewx + prj_fac2 * (ws->x1-fviewx); float py2 = fviewy + prj_fac2 * (ws->y1-fviewy); float px3 = fviewx + prj_fac2 * (ws->x2-fviewx); float py3 = fviewy + prj_fac2 * (ws->y2-fviewy); float px4 = fviewx + prj_fac1 * (ws->x2-fviewx); float py4 = fviewy + prj_fac1 * (ws->y2-fviewy); glTexCoord2f(px1 / 64, -py1 / 64); glVertex3f(px1, planez, py1); glTexCoord2f(px2 / 64, -py2 / 64); glVertex3f(px2, planez, py2); glTexCoord2f(px3 / 64, -py3 / 64); glVertex3f(px3, planez, py3); glTexCoord2f(px4 / 64, -py4 / 64); glVertex3f(px4, planez, py4); glEnd(); if (pushed) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); } }
void FGLRenderer::DrawTexture(FTexture *img, DCanvas::DrawParms &parms) { double xscale = parms.destwidth / parms.texwidth; double yscale = parms.destheight / parms.texheight; double x = parms.x - parms.left * xscale; double y = parms.y - parms.top * yscale; double w = parms.destwidth; double h = parms.destheight; float u1, v1, u2, v2, r, g, b; float light = 1.f; FMaterial * gltex = FMaterial::ValidateTexture(img); const PatchTextureInfo * pti; if (parms.colorOverlay) { // Right now there's only black. Should be implemented properly later light = 1.f - APART(parms.colorOverlay)/255.f; } if (!img->bHasCanvas) { if (!parms.alphaChannel) { int translation = 0; if (parms.remap != NULL && !parms.remap->Inactive) { GLTranslationPalette * pal = static_cast<GLTranslationPalette*>(parms.remap->GetNative()); if (pal) translation = -pal->GetIndex(); } pti = gltex->BindPatch(CM_DEFAULT, translation); } else { // This is an alpha texture pti = gltex->BindPatch(CM_SHADE, 0); } if (!pti) return; u1 = pti->GetUL(); v1 = pti->GetVT(); u2 = pti->GetUR(); v2 = pti->GetVB(); } else { gltex->Bind(CM_DEFAULT, 0, 0); u2=1.f; v2=-1.f; u1 = v1 = 0.f; gl_RenderState.SetTextureMode(TM_OPAQUE); } if (parms.flipX) { float temp = u1; u1 = u2; u2 = temp; } if (parms.windowleft > 0 || parms.windowright < parms.texwidth) { x += parms.windowleft * xscale; w -= (parms.texwidth - parms.windowright + parms.windowleft) * xscale; u1 = float(u1 + parms.windowleft / parms.texwidth); u2 = float(u2 - (parms.texwidth - parms.windowright) / parms.texwidth); } if (parms.style.Flags & STYLEF_ColorIsFixed) { r = RPART(parms.fillcolor)/255.0f; g = GPART(parms.fillcolor)/255.0f; b = BPART(parms.fillcolor)/255.0f; } else { r = g = b = light; } // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; btm = SCREENHEIGHT - btm; gl.Enable(GL_SCISSOR_TEST); int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2; gl.Scissor(parms.lclip, btm - parms.dclip + space, parms.rclip - parms.lclip, parms.dclip - parms.uclip); gl_SetRenderStyle(parms.style, !parms.masked, false); if (img->bHasCanvas) { gl_RenderState.SetTextureMode(TM_OPAQUE); } gl.Color4f(r, g, b, FIXED2FLOAT(parms.alpha)); gl_RenderState.EnableAlphaTest(false); gl_RenderState.Apply(); gl.Begin(GL_TRIANGLE_STRIP); gl.TexCoord2f(u1, v1); glVertex2d(x, y); gl.TexCoord2f(u1, v2); glVertex2d(x, y + h); gl.TexCoord2f(u2, v1); glVertex2d(x + w, y); gl.TexCoord2f(u2, v2); glVertex2d(x + w, y + h); gl.End(); gl_RenderState.EnableAlphaTest(true); gl.Scissor(0, 0, screen->GetWidth(), screen->GetHeight()); gl.Disable(GL_SCISSOR_TEST); gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.BlendEquation(GL_FUNC_ADD); }
static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, int CM_Index, bool sky2) { FSkyBox * sb = static_cast<FSkyBox*>(gltex->tex); int faces; FMaterial * tex; if (!sky2) glRotatef(-180.0f+x_offset, glset.skyrotatevector.X, glset.skyrotatevector.Z, glset.skyrotatevector.Y); else glRotatef(-180.0f+x_offset, glset.skyrotatevector2.X, glset.skyrotatevector2.Z, glset.skyrotatevector2.Y); glColor3f(R, G ,B); if (sb->faces[5]) { faces=4; // north tex = FMaterial::ValidateTexture(sb->faces[0]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, -128.f, -128.f); glTexCoord2f(0, 1); glVertex3f(128.f, -128.f, -128.f); glEnd(); // east tex = FMaterial::ValidateTexture(sb->faces[1]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, -128.f, 128.f); glTexCoord2f(0, 1); glVertex3f(-128.f, -128.f, -128.f); glEnd(); // south tex = FMaterial::ValidateTexture(sb->faces[2]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(1, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(1, 1); glVertex3f(128.f, -128.f, 128.f); glTexCoord2f(0, 1); glVertex3f(-128.f, -128.f, 128.f); glEnd(); // west tex = FMaterial::ValidateTexture(sb->faces[3]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(1, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(128.f, -128.f, -128.f); glTexCoord2f(0, 1); glVertex3f(128.f, -128.f, 128.f); glEnd(); } else { faces=1; // all 4 sides tex = FMaterial::ValidateTexture(sb->faces[0]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(.25f, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(.25f, 1); glVertex3f(-128.f, -128.f, -128.f); glTexCoord2f(0, 1); glVertex3f(128.f, -128.f, -128.f); glEnd(); // east glBegin(GL_TRIANGLE_FAN); glTexCoord2f(.25f, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(.5f, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(.5f, 1); glVertex3f(-128.f, -128.f, 128.f); glTexCoord2f(.25f, 1); glVertex3f(-128.f, -128.f, -128.f); glEnd(); // south glBegin(GL_TRIANGLE_FAN); glTexCoord2f(.5f, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(.75f, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(.75f, 1); glVertex3f(128.f, -128.f, 128.f); glTexCoord2f(.5f, 1); glVertex3f(-128.f, -128.f, 128.f); glEnd(); // west glBegin(GL_TRIANGLE_FAN); glTexCoord2f(.75f, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(1, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(128.f, -128.f, -128.f); glTexCoord2f(.75f, 1); glVertex3f(128.f, -128.f, 128.f); glEnd(); } // top tex = FMaterial::ValidateTexture(sb->faces[faces]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); if (!sb->fliptop) { glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(0, 1); glVertex3f(128.f, 128.f, 128.f); } else { glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(0, 1); glVertex3f(128.f, 128.f, -128.f); } glEnd(); // bottom tex = FMaterial::ValidateTexture(sb->faces[faces+1]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(128.f, -128.f, -128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, -128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, -128.f, 128.f); glTexCoord2f(0, 1); glVertex3f(128.f, -128.f, 128.f); glEnd(); }
void FGLInterface::PrecacheSprite(FTexture *tex, SpriteHits &hits) { FMaterial * gltex = FMaterial::ValidateTexture(tex, true); if (gltex) gltex->PrecacheList(hits); }
void FGLRenderer::DrawTexture(FTexture *img, DrawParms &parms) { double xscale = parms.destwidth / parms.texwidth; double yscale = parms.destheight / parms.texheight; double x = parms.x - parms.left * xscale; double y = parms.y - parms.top * yscale; double w = parms.destwidth; double h = parms.destheight; float u1, v1, u2, v2; int light = 255; FMaterial * gltex = FMaterial::ValidateTexture(img, false); if (parms.colorOverlay && (parms.colorOverlay & 0xffffff) == 0) { // Right now there's only black. Should be implemented properly later light = 255 - APART(parms.colorOverlay); parms.colorOverlay = 0; } gl_SetRenderStyle(parms.style, !parms.masked, false); if (!img->bHasCanvas) { int translation = 0; if (!parms.alphaChannel) { if (parms.remap != NULL && !parms.remap->Inactive) { GLTranslationPalette * pal = static_cast<GLTranslationPalette*>(parms.remap->GetNative()); if (pal) translation = -pal->GetIndex(); } } gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, translation, -1, !!(parms.style.Flags & STYLEF_RedIsAlpha)); u1 = gltex->GetUL(); v1 = gltex->GetVT(); u2 = gltex->GetUR(); v2 = gltex->GetVB(); } else { gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, 0, -1, false); u1 = 0.f; v1 = 1.f; u2 = 1.f; v2 = 0.f; gl_RenderState.SetTextureMode(TM_OPAQUE); } if (parms.flipX) { float temp = u1; u1 = u2; u2 = temp; } if (parms.windowleft > 0 || parms.windowright < parms.texwidth) { double wi = MIN(parms.windowright, parms.texwidth); x += parms.windowleft * xscale; w -= (parms.texwidth - wi + parms.windowleft) * xscale; u1 = float(u1 + parms.windowleft / parms.texwidth); u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); } PalEntry color; if (parms.style.Flags & STYLEF_ColorIsFixed) { color = parms.fillcolor; } else { color = PalEntry(light, light, light); } color.a = (BYTE)(parms.Alpha * 255); // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; btm = SCREENHEIGHT - btm; glEnable(GL_SCISSOR_TEST); int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2; glScissor(parms.lclip, btm - parms.dclip + space, parms.rclip - parms.lclip, parms.dclip - parms.uclip); gl_RenderState.SetColor(color); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); gl_RenderState.Apply(); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(x, y, 0, u1, v1); ptr++; ptr->Set(x, y + h, 0, u1, v2); ptr++; ptr->Set(x + w, y, 0, u2, v1); ptr++; ptr->Set(x + w, y + h, 0, u2, v2); ptr++; GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); if (parms.colorOverlay) { gl_RenderState.SetTextureMode(TM_MASK); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.BlendEquation(GL_FUNC_ADD); gl_RenderState.SetColor(PalEntry(parms.colorOverlay)); gl_RenderState.Apply(); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(x, y, 0, u1, v1); ptr++; ptr->Set(x, y + h, 0, u1, v2); ptr++; ptr->Set(x + w, y, 0, u2, v1); ptr++; ptr->Set(x + w, y + h, 0, u2, v2); ptr++; GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); } glScissor(0, 0, screen->GetWidth(), screen->GetHeight()); glDisable(GL_SCISSOR_TEST); gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.BlendEquation(GL_FUNC_ADD); }
void FMaterialShader::SetParameters( FRHICommandList& RHICmdList, const ShaderRHIParamRef ShaderRHI, const FMaterialRenderProxy* MaterialRenderProxy, const FMaterial& Material, const FSceneView& View, bool bDeferredPass, ESceneRenderTargetsMode::Type TextureMode) { ERHIFeatureLevel::Type FeatureLevel = View.GetFeatureLevel(); FUniformExpressionCache TempUniformExpressionCache; const FUniformExpressionCache* UniformExpressionCache = &MaterialRenderProxy->UniformExpressionCache[FeatureLevel]; SetParameters(RHICmdList, ShaderRHI, View); // If the material has cached uniform expressions for selection or hover // and that is being overridden by show flags in the editor, recache // expressions for this draw call. const bool bOverrideSelection = GIsEditor && !View.Family->EngineShowFlags.Selection && (MaterialRenderProxy->IsSelected() || MaterialRenderProxy->IsHovered()); if (!bAllowCachedUniformExpressions || !UniformExpressionCache->bUpToDate || bOverrideSelection) { FMaterialRenderContext MaterialRenderContext(MaterialRenderProxy, Material, &View); MaterialRenderProxy->EvaluateUniformExpressions(TempUniformExpressionCache, MaterialRenderContext, &RHICmdList); UniformExpressionCache = &TempUniformExpressionCache; } check(Material.GetRenderingThreadShaderMap()); check(Material.GetRenderingThreadShaderMap()->IsValidForRendering()); check(Material.GetFeatureLevel() == FeatureLevel); // Validate that the shader is being used for a material that matches the uniform expression set the shader was compiled for. const FUniformExpressionSet& MaterialUniformExpressionSet = Material.GetRenderingThreadShaderMap()->GetUniformExpressionSet(); #if NO_LOGGING == 0 const bool bUniformExpressionSetMismatch = !DebugUniformExpressionSet.Matches(MaterialUniformExpressionSet) || UniformExpressionCache->CachedUniformExpressionShaderMap != Material.GetRenderingThreadShaderMap(); if (bUniformExpressionSetMismatch) { UE_LOG( LogShaders, Fatal, TEXT("%s shader uniform expression set mismatch for material %s/%s.\n") TEXT("Shader compilation info: %s\n") TEXT("Material render proxy compilation info: %s\n") TEXT("Shader uniform expression set: %u vectors, %u scalars, %u 2D textures, %u cube textures, %u scalars/frame, %u vectors/frame, shader map %p\n") TEXT("Material uniform expression set: %u vectors, %u scalars, %u 2D textures, %u cube textures, %u scalars/frame, %u vectors/frame, shader map %p\n"), GetType()->GetName(), *MaterialRenderProxy->GetFriendlyName(), *Material.GetFriendlyName(), *DebugDescription, *Material.GetRenderingThreadShaderMap()->GetDebugDescription(), DebugUniformExpressionSet.NumVectorExpressions, DebugUniformExpressionSet.NumScalarExpressions, DebugUniformExpressionSet.Num2DTextureExpressions, DebugUniformExpressionSet.NumCubeTextureExpressions, DebugUniformExpressionSet.NumPerFrameScalarExpressions, DebugUniformExpressionSet.NumPerFrameVectorExpressions, UniformExpressionCache->CachedUniformExpressionShaderMap, MaterialUniformExpressionSet.UniformVectorExpressions.Num(), MaterialUniformExpressionSet.UniformScalarExpressions.Num(), MaterialUniformExpressionSet.Uniform2DTextureExpressions.Num(), MaterialUniformExpressionSet.UniformCubeTextureExpressions.Num(), MaterialUniformExpressionSet.PerFrameUniformScalarExpressions.Num(), MaterialUniformExpressionSet.PerFrameUniformVectorExpressions.Num(), Material.GetRenderingThreadShaderMap() ); } #endif if (UniformExpressionCache->LocalUniformBuffer.IsValid()) { // Set the material uniform buffer. SetLocalUniformBufferParameter(RHICmdList, ShaderRHI, MaterialUniformBuffer, UniformExpressionCache->LocalUniformBuffer); } else { // Set the material uniform buffer. SetUniformBufferParameter(RHICmdList, ShaderRHI, MaterialUniformBuffer, UniformExpressionCache->UniformBuffer); } { const TArray<FGuid>& ParameterCollections = UniformExpressionCache->ParameterCollections; const int32 ParameterCollectionsNum = ParameterCollections.Num(); check(ParameterCollectionUniformBuffers.Num() >= ParameterCollectionsNum); // Find each referenced parameter collection's uniform buffer in the scene and set the parameter for (int32 CollectionIndex = 0; CollectionIndex < ParameterCollectionsNum; CollectionIndex++) { FUniformBufferRHIParamRef UniformBuffer = GetParameterCollectionBuffer(ParameterCollections[CollectionIndex], View.Family->Scene); SetUniformBufferParameter(RHICmdList, ShaderRHI,ParameterCollectionUniformBuffers[CollectionIndex],UniformBuffer); } } { // Per frame material expressions const int32 NumScalarExpressions = PerFrameScalarExpressions.Num(); const int32 NumVectorExpressions = PerFrameVectorExpressions.Num(); if (NumScalarExpressions > 0 || NumVectorExpressions > 0) { FMaterialRenderContext MaterialRenderContext(MaterialRenderProxy, Material, &View); MaterialRenderContext.Time = View.Family->CurrentWorldTime; MaterialRenderContext.RealTime = View.Family->CurrentRealTime; for (int32 Index = 0; Index < NumScalarExpressions; ++Index) { auto& Parameter = PerFrameScalarExpressions[Index]; if (Parameter.IsBound()) { FLinearColor TempValue; MaterialUniformExpressionSet.PerFrameUniformScalarExpressions[Index]->GetNumberValue(MaterialRenderContext, TempValue); SetShaderValue(RHICmdList, ShaderRHI, Parameter, TempValue.R); } } for (int32 Index = 0; Index < NumVectorExpressions; ++Index) { auto& Parameter = PerFrameVectorExpressions[Index]; if (Parameter.IsBound()) { FLinearColor TempValue; MaterialUniformExpressionSet.PerFrameUniformVectorExpressions[Index]->GetNumberValue(MaterialRenderContext, TempValue); SetShaderValue(RHICmdList, ShaderRHI, Parameter, TempValue); } } // Now previous frame's expressions const int32 NumPrevScalarExpressions = PerFramePrevScalarExpressions.Num(); const int32 NumPrevVectorExpressions = PerFramePrevVectorExpressions.Num(); if (NumPrevScalarExpressions > 0 || NumPrevVectorExpressions > 0) { MaterialRenderContext.Time = View.Family->CurrentWorldTime - View.Family->DeltaWorldTime; MaterialRenderContext.RealTime = View.Family->CurrentRealTime - View.Family->DeltaWorldTime; for (int32 Index = 0; Index < NumPrevScalarExpressions; ++Index) { auto& Parameter = PerFramePrevScalarExpressions[Index]; if (Parameter.IsBound()) { FLinearColor TempValue; MaterialUniformExpressionSet.PerFramePrevUniformScalarExpressions[Index]->GetNumberValue(MaterialRenderContext, TempValue); SetShaderValue(RHICmdList, ShaderRHI, Parameter, TempValue.R); } } for (int32 Index = 0; Index < NumPrevVectorExpressions; ++Index) { auto& Parameter = PerFramePrevVectorExpressions[Index]; if (Parameter.IsBound()) { FLinearColor TempValue; MaterialUniformExpressionSet.PerFramePrevUniformVectorExpressions[Index]->GetNumberValue(MaterialRenderContext, TempValue); SetShaderValue(RHICmdList, ShaderRHI, Parameter, TempValue); } } } } } DeferredParameters.Set(RHICmdList, ShaderRHI, View, TextureMode); AtmosphericFogTextureParameters.Set(RHICmdList, ShaderRHI, View); if (FeatureLevel >= ERHIFeatureLevel::SM4) { // for copied scene color if(LightAttenuation.IsBound()) { SetTextureParameter( RHICmdList, ShaderRHI, LightAttenuation, LightAttenuationSampler, TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(), GSceneRenderTargets.GetLightAttenuationTexture()); } } //Use of the eye adaptation texture here is experimental and potentially dangerous as it can introduce a feedback loop. May be removed. if(EyeAdaptation.IsBound()) { FTextureRHIRef& EyeAdaptationTex = GetEyeAdaptation(View); SetTextureParameter(RHICmdList, ShaderRHI, EyeAdaptation, EyeAdaptationTex); } if (PerlinNoiseGradientTexture.IsBound() && IsValidRef(GSystemTextures.PerlinNoiseGradient)) { const FTexture2DRHIRef& Texture = (FTexture2DRHIRef&)GSystemTextures.PerlinNoiseGradient->GetRenderTargetItem().ShaderResourceTexture; // Bind the PerlinNoiseGradientTexture as a texture SetTextureParameter( RHICmdList, ShaderRHI, PerlinNoiseGradientTexture, PerlinNoiseGradientTextureSampler, TStaticSamplerState<SF_Point,AM_Wrap,AM_Wrap,AM_Wrap>::GetRHI(), Texture ); } if (PerlinNoise3DTexture.IsBound() && IsValidRef(GSystemTextures.PerlinNoise3D)) { const FTexture3DRHIRef& Texture = (FTexture3DRHIRef&)GSystemTextures.PerlinNoise3D->GetRenderTargetItem().ShaderResourceTexture; // Bind the PerlinNoise3DTexture as a texture SetTextureParameter( RHICmdList, ShaderRHI, PerlinNoise3DTexture, PerlinNoise3DTextureSampler, TStaticSamplerState<SF_Bilinear,AM_Wrap,AM_Wrap,AM_Wrap>::GetRHI(), Texture ); } GlobalDistanceFieldParameters.Set(RHICmdList, ShaderRHI, static_cast<const FViewInfo&>(View).GlobalDistanceFieldInfo.ParameterData); }
//========================================================================== // // Draw the plane segment into the gap // //========================================================================== void FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) { GLSectorPlane plane; int lightlevel; FColormap Colormap; FMaterial * gltexture; plane.GetFromSector(sec, ceiling); gltexture=FMaterial::ValidateTexture(plane.texture, true); if (!gltexture) return; if (gl_fixedcolormap) { Colormap.Clear(); lightlevel=255; } else { Colormap=sec->ColorMap; if (gltexture->tex->isFullbright()) { Colormap.LightColor.r = Colormap.LightColor.g = Colormap.LightColor.b = 0xff; lightlevel=255; } else lightlevel=abs(ceiling? sec->GetCeilingLight() : sec->GetFloorLight()); } int rel = getExtraLight(); gl_SetColor(lightlevel, rel, Colormap, 1.0f); gl_SetFog(lightlevel, rel, &Colormap, false); gltexture->Bind(); float fviewx = FIXED2FLOAT(viewx); float fviewy = FIXED2FLOAT(viewy); float fviewz = FIXED2FLOAT(viewz); gl_SetPlaneTextureRotation(&plane, gltexture); gl_RenderState.Apply(); float prj_fac1 = (planez-fviewz)/(ws->z1-fviewz); float prj_fac2 = (planez-fviewz)/(ws->z2-fviewz); float px1 = fviewx + prj_fac1 * (ws->x1-fviewx); float py1 = fviewy + prj_fac1 * (ws->y1-fviewy); float px2 = fviewx + prj_fac2 * (ws->x1-fviewx); float py2 = fviewy + prj_fac2 * (ws->y1-fviewy); float px3 = fviewx + prj_fac2 * (ws->x2-fviewx); float py3 = fviewy + prj_fac2 * (ws->y2-fviewy); float px4 = fviewx + prj_fac1 * (ws->x2-fviewx); float py4 = fviewy + prj_fac1 * (ws->y2-fviewy); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(px1, planez, py1, px1 / 64, -py1 / 64); ptr++; ptr->Set(px2, planez, py2, px2 / 64, -py2 / 64); ptr++; ptr->Set(px3, planez, py3, px3 / 64, -py3 / 64); ptr++; ptr->Set(px4, planez, py4, px4 / 64, -py4 / 64); ptr++; GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); gl_RenderState.EnableTextureMatrix(false); }
//========================================================================== // // // //========================================================================== void GLWall::DrawDecal(DBaseDecal *decal) { line_t * line=seg->linedef; side_t * side=seg->sidedef; int i; float zpos; int light; int rel; float a; bool flipx, flipy; DecalVertex dv[4]; FTextureID decalTile; if (decal->RenderFlags & RF_INVISIBLE) return; if (type==RENDERWALL_FFBLOCK && gltexture->isMasked()) return; // No decals on 3D floors with transparent textures. //if (decal->sprite != 0xffff) { decalTile = decal->PicNum; flipx = !!(decal->RenderFlags & RF_XFLIP); flipy = !!(decal->RenderFlags & RF_YFLIP); } /* else { decalTile = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].lump[0]; flipx = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].flip & 1; } */ FTexture *texture = TexMan[decalTile]; if (texture == NULL) return; FMaterial *tex; tex = FMaterial::ValidateTexture(texture, true); // the sectors are only used for their texture origin coordinates // so we don't need the fake sectors for deep water etc. // As this is a completely split wall fragment no further splits are // necessary for the decal. sector_t *frontsector; // for 3d-floor segments use the model sector as reference if ((decal->RenderFlags&RF_CLIPMASK)==RF_CLIPMID) frontsector=decal->Sector; else frontsector=seg->frontsector; switch (decal->RenderFlags & RF_RELMASK) { default: // No valid decal can have this type. If one is encountered anyway // it is in some way invalid so skip it. return; //zpos = decal->z; //break; case RF_RELUPPER: if (type!=RENDERWALL_TOP) return; if (line->flags & ML_DONTPEGTOP) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } else { zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::ceiling); } break; case RF_RELLOWER: if (type!=RENDERWALL_BOTTOM) return; if (line->flags & ML_DONTPEGBOTTOM) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } else { zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::floor); } break; case RF_RELMID: if (type==RENDERWALL_TOP || type==RENDERWALL_BOTTOM) return; if (line->flags & ML_DONTPEGBOTTOM) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::floor); } else { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } } if (decal->RenderFlags & RF_FULLBRIGHT) { light = 255; rel = 0; } else { light = lightlevel; rel = rellight + getExtraLight(); } FColormap p = Colormap; if (glset.nocoloredspritelighting) { p.Decolorize(); } a = decal->Alpha; // now clip the decal to the actual polygon float decalwidth = tex->TextureWidth() * decal->ScaleX; float decalheight= tex->TextureHeight() * decal->ScaleY; float decallefto = tex->GetLeftOffset() * decal->ScaleX; float decaltopo = tex->GetTopOffset() * decal->ScaleY; float leftedge = glseg.fracleft * side->TexelLength; float linelength = glseg.fracright * side->TexelLength - leftedge; // texel index of the decal's left edge float decalpixpos = (float)side->TexelLength * decal->LeftDistance - (flipx? decalwidth-decallefto : decallefto) - leftedge; float left,right; float lefttex,righttex; // decal is off the left edge if (decalpixpos < 0) { left = 0; lefttex = -decalpixpos; } else { left = decalpixpos; lefttex = 0; } // decal is off the right edge if (decalpixpos + decalwidth > linelength) { right = linelength; righttex = right - decalpixpos; } else { right = decalpixpos + decalwidth; righttex = decalwidth; } if (right<=left) return; // nothing to draw // one texture unit on the wall as vector float vx=(glseg.x2-glseg.x1)/linelength; float vy=(glseg.y2-glseg.y1)/linelength; dv[1].x=dv[0].x=glseg.x1+vx*left; dv[1].y=dv[0].y=glseg.y1+vy*left; dv[3].x=dv[2].x=glseg.x1+vx*right; dv[3].y=dv[2].y=glseg.y1+vy*right; zpos+= (flipy? decalheight-decaltopo : decaltopo); dv[1].z=dv[2].z = zpos; dv[0].z=dv[3].z = dv[1].z - decalheight; dv[1].v=dv[2].v = tex->GetVT(); dv[1].u=dv[0].u = tex->GetU(lefttex / decal->ScaleX); dv[3].u=dv[2].u = tex->GetU(righttex / decal->ScaleX); dv[0].v=dv[3].v = tex->GetVB(); // now clip to the top plane float vzt=(ztop[1]-ztop[0])/linelength; float topleft=this->ztop[0]+vzt*left; float topright=this->ztop[0]+vzt*right; // completely below the wall if (topleft<dv[0].z && topright<dv[3].z) return; if (topleft<dv[1].z || topright<dv[2].z) { // decal has to be clipped at the top // let texture clamping handle all extreme cases dv[1].v=(dv[1].z-topleft)/(dv[1].z-dv[0].z)*dv[0].v; dv[2].v=(dv[2].z-topright)/(dv[2].z-dv[3].z)*dv[3].v; dv[1].z=topleft; dv[2].z=topright; } // now clip to the bottom plane float vzb=(zbottom[1]-zbottom[0])/linelength; float bottomleft=this->zbottom[0]+vzb*left; float bottomright=this->zbottom[0]+vzb*right; // completely above the wall if (bottomleft>dv[1].z && bottomright>dv[2].z) return; if (bottomleft>dv[0].z || bottomright>dv[3].z) { // decal has to be clipped at the bottom // let texture clamping handle all extreme cases dv[0].v=(dv[1].z-bottomleft)/(dv[1].z-dv[0].z)*(dv[0].v-dv[1].v) + dv[1].v; dv[3].v=(dv[2].z-bottomright)/(dv[2].z-dv[3].z)*(dv[3].v-dv[2].v) + dv[2].v; dv[0].z=bottomleft; dv[3].z=bottomright; } if (flipx) { float ur = tex->GetUR(); for(i=0;i<4;i++) dv[i].u=ur-dv[i].u; } if (flipy) { float vb = tex->GetVB(); for(i=0;i<4;i++) dv[i].v=vb-dv[i].v; } // calculate dynamic light effect. if (gl_lights && GLRenderer->mLightCount && !gl_fixedcolormap && gl_light_sprites) { // Note: This should be replaced with proper shader based lighting. double x, y; decal->GetXY(seg->sidedef, x, y); gl_SetDynSpriteLight(NULL, x, y, zpos, sub); } // alpha color only has an effect when using an alpha texture. if (decal->RenderStyle.Flags & STYLEF_RedIsAlpha) { gl_RenderState.SetObjectColor(decal->AlphaColor|0xff000000); } gl_SetRenderStyle(decal->RenderStyle, false, false); gl_RenderState.SetMaterial(tex, CLAMP_XY, decal->Translation, 0, !!(decal->RenderStyle.Flags & STYLEF_RedIsAlpha)); // If srcalpha is one it looks better with a higher alpha threshold if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold); else gl_RenderState.AlphaFunc(GL_GREATER, 0.f); gl_SetColor(light, rel, p, a); // for additively drawn decals we must temporarily set the fog color to black. PalEntry fc = gl_RenderState.GetFogColor(); if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One) { gl_RenderState.SetFog(0,-1); } FQuadDrawer qd; for (i = 0; i < 4; i++) { qd.Set(i, dv[i].x, dv[i].z, dv[i].y, dv[i].u, dv[i].v); } if (lightlist == NULL) { gl_RenderState.Apply(); qd.Render(GL_TRIANGLE_FAN); } else { for (unsigned k = 0; k < lightlist->Size(); k++) { secplane_t &lowplane = k == (*lightlist).Size() - 1 ? bottomplane : (*lightlist)[k + 1].plane; float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y); float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y); if (low1 < dv[1].z || low2 < dv[2].z) { int thisll = (*lightlist)[k].caster != NULL ? gl_ClampLight(*(*lightlist)[k].p_lightlevel) : lightlevel; FColormap thiscm; thiscm.FadeColor = Colormap.FadeColor; thiscm.CopyFrom3DLight(&(*lightlist)[k]); gl_SetColor(thisll, rel, thiscm, a); if (glset.nocoloredspritelighting) thiscm.Decolorize(); gl_SetFog(thisll, rel, &thiscm, RenderStyle == STYLE_Add); gl_RenderState.SetSplitPlanes((*lightlist)[k].plane, lowplane); gl_RenderState.Apply(); qd.Render(GL_TRIANGLE_FAN); } if (low1 <= dv[0].z && low2 <= dv[3].z) break; } } rendered_decals++; gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.SetObjectColor(0xffffffff); gl_RenderState.SetFog(fc,-1); gl_RenderState.SetDynLight(0,0,0); }
void FGLRenderer::DrawPSprite (player_t * player,DPSprite *psp, float sx, float sy, bool hudModelStep, int OverrideShader, bool alphatexture) { float fU1,fV1; float fU2,fV2; float tx; float x1,y1,x2,y2; float scale; float scalex; float ftexturemid; // 4:3 16:9 16:10 17:10 5:4 17:10 21:9 static float xratio[] = {1.f, 3.f/4, 5.f/6, 40.f/51, 1.f, 40.f/51, 4.f/7}; // [BB] In the HUD model step we just render the model and break out. if ( hudModelStep ) { gl_RenderHUDModel(psp, sx, sy); return; } // decide which patch to use bool mirror; FTextureID lump = gl_GetSpriteFrame(psp->GetSprite(), psp->GetFrame(), 0, 0, &mirror); if (!lump.isValid()) return; FMaterial * tex = FMaterial::ValidateTexture(lump, true, false); if (!tex) return; gl_RenderState.SetMaterial(tex, CLAMP_XY_NOMIP, 0, OverrideShader, alphatexture); float vw = (float)viewwidth; float vh = (float)viewheight; FloatRect r; tex->GetSpriteRect(&r); // calculate edges of the shape scalex = xratio[WidescreenRatio] * vw / 320; tx = sx - (160 - r.left); x1 = tx * scalex + vw/2; if (x1 > vw) return; // off the right side x1 += viewwindowx; tx += r.width; x2 = tx * scalex + vw / 2; if (x2 < 0) return; // off the left side x2 += viewwindowx; // killough 12/98: fix psprite positioning problem ftexturemid = 100.f - sy - r.top; AWeapon * wi=player->ReadyWeapon; if (wi && wi->YAdjust != 0) { float fYAd = wi->YAdjust; if (screenblocks >= 11) { ftexturemid -= fYAd; } else if (!st_scale) { ftexturemid -= StatusBar->GetDisplacement () * fYAd; } } scale = (SCREENHEIGHT*vw) / (SCREENWIDTH * 200.0f); y1 = viewwindowy + vh / 2 - (ftexturemid * scale); y2 = y1 + (r.height * scale) + 1; if (!mirror) { fU1=tex->GetSpriteUL(); fV1=tex->GetSpriteVT(); fU2=tex->GetSpriteUR(); fV2=tex->GetSpriteVB(); } else { fU2=tex->GetSpriteUL(); fV1=tex->GetSpriteVT(); fU1=tex->GetSpriteUR(); fV2=tex->GetSpriteVB(); } if (tex->GetTransparent() || OverrideShader != -1) { gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); } gl_RenderState.Apply(); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(x1, y1, 0, fU1, fV1); ptr++; ptr->Set(x1, y2, 0, fU1, fV2); ptr++; ptr->Set(x2, y1, 0, fU2, fV1); ptr++; ptr->Set(x2, y2, 0, fU2, fV2); ptr++; GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f); }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // // Horizon Portal // // This simply draws the area in medium sized squares. Drawing it as a whole // polygon creates visible inaccuracies. // // Originally I tried to minimize the amount of data to be drawn but there // are 2 problems with it: // // 1. Setting this up completely negates any performance gains. // 2. It doesn't work with a 360° field of view (as when you are looking up.) // // // So the brute force mechanism is just as good. // // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // GLHorizonPortal::DrawContents // //----------------------------------------------------------------------------- void GLHorizonPortal::DrawContents() { PortalAll.Clock(); GLSectorPlane * sp=&origin->plane; FMaterial * gltexture; PalEntry color; float z; player_t * player=&players[consoleplayer]; gltexture=FMaterial::ValidateTexture(sp->texture, true); if (!gltexture) { ClearScreen(); PortalAll.Unclock(); return; } z=FIXED2FLOAT(sp->texheight); if (gltexture && gltexture->tex->isFullbright()) { // glowing textures are always drawn full bright without color gl_SetColor(255, 0, NULL, 1.f); gl_SetFog(255, 0, &origin->colormap, false); } else { int rel = getExtraLight(); gl_SetColor(origin->lightlevel, rel, &origin->colormap, 1.0f); gl_SetFog(origin->lightlevel, rel, &origin->colormap, false); } gltexture->Bind(origin->colormap.colormap); gl_RenderState.EnableAlphaTest(false); gl_RenderState.BlendFunc(GL_ONE,GL_ZERO); gl_RenderState.Apply(); bool pushed = gl_SetPlaneTextureRotation(sp, gltexture); float vx=FIXED2FLOAT(viewx); float vy=FIXED2FLOAT(viewy); // Draw to some far away boundary for(float x=-32768+vx; x<32768+vx; x+=4096) { for(float y=-32768+vy; y<32768+vy;y+=4096) { glBegin(GL_TRIANGLE_FAN); glTexCoord2f(x/64, -y/64); glVertex3f(x, z, y); glTexCoord2f(x/64 + 64, -y/64); glVertex3f(x + 4096, z, y); glTexCoord2f(x/64 + 64, -y/64 - 64); glVertex3f(x + 4096, z, y + 4096); glTexCoord2f(x/64, -y/64 - 64); glVertex3f(x, z, y + 4096); glEnd(); } } float vz=FIXED2FLOAT(viewz); float tz=(z-vz);///64.0f; // fill the gap between the polygon and the true horizon // Since I can't draw into infinity there can always be a // small gap glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(512.f, 0); glVertex3f(-32768+vx, z, -32768+vy); glTexCoord2f(512.f, tz); glVertex3f(-32768+vx, vz, -32768+vy); glTexCoord2f(-512.f, 0); glVertex3f(-32768+vx, z, 32768+vy); glTexCoord2f(-512.f, tz); glVertex3f(-32768+vx, vz, 32768+vy); glTexCoord2f(512.f, 0); glVertex3f( 32768+vx, z, 32768+vy); glTexCoord2f(512.f, tz); glVertex3f( 32768+vx, vz, 32768+vy); glTexCoord2f(-512.f, 0); glVertex3f( 32768+vx, z, -32768+vy); glTexCoord2f(-512.f, tz); glVertex3f( 32768+vx, vz, -32768+vy); glTexCoord2f(512.f, 0); glVertex3f(-32768+vx, z, -32768+vy); glTexCoord2f(512.f, tz); glVertex3f(-32768+vx, vz, -32768+vy); glEnd(); if (pushed) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); } PortalAll.Unclock(); }
//========================================================================== // // // //========================================================================== void GLWall::DrawDecal(DBaseDecal *decal) { line_t * line=seg->linedef; side_t * side=seg->sidedef; int i; fixed_t zpos; int light; int rel; float a; bool flipx, flipy, loadAlpha; DecalVertex dv[4]; FTextureID decalTile; if (decal->RenderFlags & RF_INVISIBLE) return; if (type==RENDERWALL_FFBLOCK && gltexture->isMasked()) return; // No decals on 3D floors with transparent textures. //if (decal->sprite != 0xffff) { decalTile = decal->PicNum; flipx = !!(decal->RenderFlags & RF_XFLIP); flipy = !!(decal->RenderFlags & RF_YFLIP); } /* else { decalTile = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].lump[0]; flipx = SpriteFrames[sprites[decal->sprite].spriteframes + decal->frame].flip & 1; } */ FTexture *texture = TexMan[decalTile]; if (texture == NULL) return; FMaterial *tex; if (texture->UseType == FTexture::TEX_MiscPatch) { // We need to create a clone of this texture where we can force the // texture filtering offset in. if (texture->gl_info.DecalTexture == NULL) { texture->gl_info.DecalTexture = new FCloneTexture(texture, FTexture::TEX_Decal); } tex = FMaterial::ValidateTexture(texture->gl_info.DecalTexture); } else tex = FMaterial::ValidateTexture(texture); // the sectors are only used for their texture origin coordinates // so we don't need the fake sectors for deep water etc. // As this is a completely split wall fragment no further splits are // necessary for the decal. sector_t *frontsector; // for 3d-floor segments use the model sector as reference if ((decal->RenderFlags&RF_CLIPMASK)==RF_CLIPMID) frontsector=decal->Sector; else frontsector=seg->frontsector; switch (decal->RenderFlags & RF_RELMASK) { default: // No valid decal can have this type. If one is encountered anyway // it is in some way invalid so skip it. return; //zpos = decal->z; //break; case RF_RELUPPER: if (type!=RENDERWALL_TOP) return; if (line->flags & ML_DONTPEGTOP) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } else { zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::ceiling); } break; case RF_RELLOWER: if (type!=RENDERWALL_BOTTOM) return; if (line->flags & ML_DONTPEGBOTTOM) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } else { zpos = decal->Z + seg->backsector->GetPlaneTexZ(sector_t::floor); } break; case RF_RELMID: if (type==RENDERWALL_TOP || type==RENDERWALL_BOTTOM) return; if (line->flags & ML_DONTPEGBOTTOM) { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::floor); } else { zpos = decal->Z + frontsector->GetPlaneTexZ(sector_t::ceiling); } } if (decal->RenderFlags & RF_FULLBRIGHT) { light = 255; rel = 0; } else { light = lightlevel; rel = rellight + getExtraLight(); } int r = RPART(decal->AlphaColor); int g = GPART(decal->AlphaColor); int b = BPART(decal->AlphaColor); FColormap p = Colormap; if (glset.nocoloredspritelighting) { int v = (Colormap.LightColor.r * 77 + Colormap.LightColor.g*143 + Colormap.LightColor.b*35)/255; p.LightColor = PalEntry(p.colormap, v, v, v); } float red, green, blue; if (decal->RenderStyle.Flags & STYLEF_RedIsAlpha) { loadAlpha = true; p.colormap=CM_SHADE; if (glset.lightmode != 8) { gl_GetLightColor(light, rel, &p, &red, &green, &blue); } else { gl_GetLightColor(lightlevel, rellight, &p, &red, &green, &blue); } if (gl_lights && GLRenderer->mLightCount && !gl_fixedcolormap && gl_light_sprites) { float result[3]; fixed_t x, y; decal->GetXY(seg->sidedef, x, y); gl_GetSpriteLight(NULL, x, y, zpos, sub, Colormap.colormap-CM_DESAT0, result, line, side == line->sidedef[0]? 0:1); if (glset.lightmode != 8) { red = clamp<float>(result[0]+red, 0, 1.0f); green = clamp<float>(result[1]+green, 0, 1.0f); blue = clamp<float>(result[2]+blue, 0, 1.0f); } else { gl_RenderState.SetDynLight(result[0], result[1], result[2]); } } BYTE R = xs_RoundToInt(r * red); BYTE G = xs_RoundToInt(g * green); BYTE B = xs_RoundToInt(b * blue); gl_ModifyColor(R,G,B, Colormap.colormap); red = R/255.f; green = G/255.f; blue = B/255.f; } else { loadAlpha = false; red = 1.f; green = 1.f; blue = 1.f; } a = FIXED2FLOAT(decal->Alpha); // now clip the decal to the actual polygon float decalwidth = tex->TextureWidth(GLUSE_PATCH) * FIXED2FLOAT(decal->ScaleX); float decalheight= tex->TextureHeight(GLUSE_PATCH) * FIXED2FLOAT(decal->ScaleY); float decallefto = tex->GetLeftOffset(GLUSE_PATCH) * FIXED2FLOAT(decal->ScaleX); float decaltopo = tex->GetTopOffset(GLUSE_PATCH) * FIXED2FLOAT(decal->ScaleY); float leftedge = glseg.fracleft * side->TexelLength; float linelength = glseg.fracright * side->TexelLength - leftedge; // texel index of the decal's left edge float decalpixpos = (float)side->TexelLength * decal->LeftDistance / (1<<30) - (flipx? decalwidth-decallefto : decallefto) - leftedge; float left,right; float lefttex,righttex; // decal is off the left edge if (decalpixpos < 0) { left = 0; lefttex = -decalpixpos; } else { left = decalpixpos; lefttex = 0; } // decal is off the right edge if (decalpixpos + decalwidth > linelength) { right = linelength; righttex = right - decalpixpos; } else { right = decalpixpos + decalwidth; righttex = decalwidth; } if (right<=left) return; // nothing to draw // one texture unit on the wall as vector float vx=(glseg.x2-glseg.x1)/linelength; float vy=(glseg.y2-glseg.y1)/linelength; dv[1].x=dv[0].x=glseg.x1+vx*left; dv[1].y=dv[0].y=glseg.y1+vy*left; dv[3].x=dv[2].x=glseg.x1+vx*right; dv[3].y=dv[2].y=glseg.y1+vy*right; zpos+= FRACUNIT*(flipy? decalheight-decaltopo : decaltopo); tex->BindPatch(p.colormap, decal->Translation); dv[1].z=dv[2].z = FIXED2FLOAT(zpos); dv[0].z=dv[3].z = dv[1].z - decalheight; dv[1].v=dv[2].v = tex->GetVT(); dv[1].u=dv[0].u = tex->GetU(lefttex / FIXED2FLOAT(decal->ScaleX)); dv[3].u=dv[2].u = tex->GetU(righttex / FIXED2FLOAT(decal->ScaleX)); dv[0].v=dv[3].v = tex->GetVB(); // now clip to the top plane float vzt=(ztop[1]-ztop[0])/linelength; float topleft=this->ztop[0]+vzt*left; float topright=this->ztop[0]+vzt*right; // completely below the wall if (topleft<dv[0].z && topright<dv[3].z) return; if (topleft<dv[1].z || topright<dv[2].z) { // decal has to be clipped at the top // let texture clamping handle all extreme cases dv[1].v=(dv[1].z-topleft)/(dv[1].z-dv[0].z)*dv[0].v; dv[2].v=(dv[2].z-topright)/(dv[2].z-dv[3].z)*dv[3].v; dv[1].z=topleft; dv[2].z=topright; } // now clip to the bottom plane float vzb=(zbottom[1]-zbottom[0])/linelength; float bottomleft=this->zbottom[0]+vzb*left; float bottomright=this->zbottom[0]+vzb*right; // completely above the wall if (bottomleft>dv[1].z && bottomright>dv[2].z) return; if (bottomleft>dv[0].z || bottomright>dv[3].z) { // decal has to be clipped at the bottom // let texture clamping handle all extreme cases dv[0].v=(dv[1].z-bottomleft)/(dv[1].z-dv[0].z)*(dv[0].v-dv[1].v) + dv[1].v; dv[3].v=(dv[2].z-bottomright)/(dv[2].z-dv[3].z)*(dv[3].v-dv[2].v) + dv[2].v; dv[0].z=bottomleft; dv[3].z=bottomright; } if (flipx) { float ur = tex->GetUR(); for(i=0;i<4;i++) dv[i].u=ur-dv[i].u; } if (flipy) { float vb = tex->GetVB(); for(i=0;i<4;i++) dv[i].v=vb-dv[i].v; } // fog is set once per wall in the calling function and not per decal! if (loadAlpha) { glColor4f(red, green, blue, a); if (glset.lightmode == 8) { if (gl_fixedcolormap) glVertexAttrib1f(VATTR_LIGHTLEVEL, 1.0); else glVertexAttrib1f(VATTR_LIGHTLEVEL, gl_CalcLightLevel(light, rel, false) / 255.0); } } else { if (glset.lightmode == 8) { gl_SetColor(light, rel, &p, a, extralight); // Korshun. } else { gl_SetColor(light, rel, &p, a); } } PalEntry fc = gl_RenderState.GetFogColor(); if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One) { gl_RenderState.SetFog(0,-1); } gl_SetRenderStyle(decal->RenderStyle, false, false); // If srcalpha is one it looks better with a higher alpha threshold if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold); else gl_RenderState.AlphaFunc(GL_GREATER, 0.f); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); for(i=0;i<4;i++) { glTexCoord2f(dv[i].u,dv[i].v); glVertex3f(dv[i].x,dv[i].z,dv[i].y); } glEnd(); rendered_decals++; gl_RenderState.SetFog(fc,-1); gl_RenderState.SetDynLight(0,0,0); }