1 /* Copyright (C) 2022 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
22 #include "lib/code_annotation.h"
23 #include "lib/config2.h"
24 #include "lib/res/graphics/ogl_tex.h"
25 #include "renderer/backend/gl/Device.h"
39 GLint
CalculateMinFilter(const Sampler::Desc
& defaultSamplerDesc
, const uint32_t mipCount
)
42 return defaultSamplerDesc
.minFilter
== Sampler::Filter::LINEAR
? GL_LINEAR
: GL_NEAREST
;
44 if (defaultSamplerDesc
.minFilter
== Sampler::Filter::LINEAR
)
45 return defaultSamplerDesc
.mipFilter
== Sampler::Filter::LINEAR
? GL_LINEAR_MIPMAP_LINEAR
: GL_LINEAR_MIPMAP_NEAREST
;
47 return defaultSamplerDesc
.mipFilter
== Sampler::Filter::LINEAR
? GL_NEAREST_MIPMAP_LINEAR
: GL_NEAREST_MIPMAP_NEAREST
;
50 GLint
AddressModeToGLEnum(Sampler::AddressMode addressMode
)
54 case Sampler::AddressMode::REPEAT
: return GL_REPEAT
;
55 case Sampler::AddressMode::MIRRORED_REPEAT
: return GL_MIRRORED_REPEAT
;
56 case Sampler::AddressMode::CLAMP_TO_EDGE
: return GL_CLAMP_TO_EDGE
;
57 case Sampler::AddressMode::CLAMP_TO_BORDER
: return GL_CLAMP_TO_BORDER
;
62 GLenum
TypeToGLEnum(CTexture::Type type
)
64 GLenum target
= GL_TEXTURE_2D
;
67 case CTexture::Type::TEXTURE_2D
:
68 target
= GL_TEXTURE_2D
;
70 case CTexture::Type::TEXTURE_2D_MULTISAMPLE
:
72 ENSURE(false && "Multisample textures are unsupported on GLES");
74 target
= GL_TEXTURE_2D_MULTISAMPLE
;
77 case CTexture::Type::TEXTURE_CUBE
:
78 target
= GL_TEXTURE_CUBE_MAP
;
84 } // anonymous namespace
87 std::unique_ptr
<CTexture
> CTexture::Create2D(const Format format
,
88 const uint32_t width
, const uint32_t height
,
89 const Sampler::Desc
& defaultSamplerDesc
, const uint32_t mipCount
, const uint32_t sampleCount
)
91 return Create(Type::TEXTURE_2D
, format
, width
, height
, defaultSamplerDesc
, mipCount
, sampleCount
);
95 std::unique_ptr
<CTexture
> CTexture::Create(const Type type
, const Format format
,
96 const uint32_t width
, const uint32_t height
,
97 const Sampler::Desc
& defaultSamplerDesc
, const uint32_t mipCount
, const uint32_t sampleCount
)
99 std::unique_ptr
<CTexture
> texture(new CTexture());
101 ENSURE(format
!= Format::UNDEFINED
);
102 ENSURE(width
> 0 && height
> 0 && mipCount
> 0);
103 ENSURE((type
== Type::TEXTURE_2D_MULTISAMPLE
&& sampleCount
> 1) || sampleCount
== 1);
105 texture
->m_Format
= format
;
106 texture
->m_Width
= width
;
107 texture
->m_Height
= height
;
108 texture
->m_MipCount
= mipCount
;
110 glGenTextures(1, &texture
->m_Handle
);
114 glActiveTextureARB(GL_TEXTURE0
);
116 const GLenum target
= TypeToGLEnum(type
);
118 glBindTexture(target
, texture
->m_Handle
);
120 // It's forbidden to set sampler state for multisample textures.
121 if (type
!= Type::TEXTURE_2D_MULTISAMPLE
)
123 glTexParameteri(target
, GL_TEXTURE_MIN_FILTER
, CalculateMinFilter(defaultSamplerDesc
, mipCount
));
124 glTexParameteri(target
, GL_TEXTURE_MAG_FILTER
, defaultSamplerDesc
.magFilter
== Sampler::Filter::LINEAR
? GL_LINEAR
: GL_NEAREST
);
128 glTexParameteri(target
, GL_TEXTURE_WRAP_S
, AddressModeToGLEnum(defaultSamplerDesc
.addressModeU
));
129 glTexParameteri(target
, GL_TEXTURE_WRAP_T
, AddressModeToGLEnum(defaultSamplerDesc
.addressModeV
));
133 if (type
== Type::TEXTURE_CUBE
)
134 glTexParameteri(target
, GL_TEXTURE_WRAP_R
, AddressModeToGLEnum(defaultSamplerDesc
.addressModeW
));
140 glTexParameteri(target
, GL_TEXTURE_BASE_LEVEL
, 0);
141 glTexParameteri(target
, GL_TEXTURE_MAX_LEVEL
, mipCount
- 1);
143 if (defaultSamplerDesc
.mipLODBias
!= 0.0f
)
144 glTexParameteri(target
, GL_TEXTURE_LOD_BIAS
, defaultSamplerDesc
.mipLODBias
);
145 #endif // !CONFIG2_GLES
147 if (type
== Type::TEXTURE_2D
&& defaultSamplerDesc
.anisotropyEnabled
&& ogl_tex_has_anisotropy())
148 glTexParameterf(target
, GL_TEXTURE_MAX_ANISOTROPY_EXT
, defaultSamplerDesc
.maxAnisotropy
);
150 if (defaultSamplerDesc
.addressModeU
== Sampler::AddressMode::CLAMP_TO_BORDER
||
151 defaultSamplerDesc
.addressModeV
== Sampler::AddressMode::CLAMP_TO_BORDER
||
152 defaultSamplerDesc
.addressModeW
== Sampler::AddressMode::CLAMP_TO_BORDER
)
154 glTexParameterfv(target
, GL_TEXTURE_BORDER_COLOR
, defaultSamplerDesc
.borderColor
.AsFloatArray());
159 ENSURE(mipCount
== 1);
161 if (type
== CTexture::Type::TEXTURE_2D
)
163 GLint internalFormat
= GL_RGBA
;
164 // Actually pixel data is nullptr so it doesn't make sense to account
165 // it, but in theory some buggy drivers might complain about invalid
167 GLenum pixelFormat
= GL_RGBA
;
168 GLenum pixelType
= GL_UNSIGNED_BYTE
;
171 case Format::UNDEFINED
:
172 debug_warn("Texture should defined format");
174 case Format::R8G8B8A8
:
177 internalFormat
= GL_ALPHA
;
178 pixelFormat
= GL_ALPHA
;
179 pixelType
= GL_UNSIGNED_BYTE
;
182 // GLES requires pixel type == UNSIGNED_SHORT or UNSIGNED_INT for depth.
183 case Format::D16
: FALLTHROUGH
;
184 case Format::D24
: FALLTHROUGH
;
186 internalFormat
= GL_DEPTH_COMPONENT
;
187 pixelFormat
= GL_DEPTH_COMPONENT
;
188 pixelType
= GL_UNSIGNED_SHORT
;
191 debug_warn("Unsupported format");
195 internalFormat
= GL_DEPTH_COMPONENT16
;
196 pixelFormat
= GL_DEPTH_COMPONENT
;
197 pixelType
= GL_UNSIGNED_SHORT
;
200 internalFormat
= GL_DEPTH_COMPONENT24
;
201 pixelFormat
= GL_DEPTH_COMPONENT
;
202 pixelType
= GL_UNSIGNED_SHORT
;
205 internalFormat
= GL_DEPTH_COMPONENT32
;
206 pixelFormat
= GL_DEPTH_COMPONENT
;
207 pixelType
= GL_UNSIGNED_SHORT
;
210 internalFormat
= GL_DEPTH24_STENCIL8_EXT
;
211 pixelFormat
= GL_DEPTH_STENCIL_EXT
;
212 pixelType
= GL_UNSIGNED_INT_24_8_EXT
;
216 glTexImage2D(target
, 0, internalFormat
, width
, height
, 0, pixelFormat
, pixelType
, nullptr);
218 else if (type
== CTexture::Type::TEXTURE_2D_MULTISAMPLE
)
221 if (format
== Format::R8G8B8A8
)
223 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE
, sampleCount
, GL_RGBA8
, width
, height
, GL_TRUE
);
225 else if (format
== Format::D24_S8
)
227 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE
, sampleCount
, GL_DEPTH24_STENCIL8_EXT
, width
, height
, GL_TRUE
);
230 #endif // !CONFIG2_GLES
232 debug_warn("Unsupported format");
238 glBindTexture(target
, 0);
243 CTexture::CTexture() = default;
245 CTexture::~CTexture()
248 glDeleteTextures(1, &m_Handle
);
253 } // namespace Backend
255 } // namespace Renderer