Covellite++  Version: 2.3.2 Revision: 2584 Platform: x64 Build: 19:03 05.09.2026
Кроссплатформенный фреймворк для разработки приложений на С++
Загрузка...
Поиск...
Не найдено
OpenGLCommonShader.cpp
1
2#include "stdafx.h"
3#include "OpenGLCommonShader.hpp"
4#include <glm/glm.force.hpp>
5#include <alicorn/std/vector.hpp>
6#include <alicorn/std.fast/unordered-map.hpp>
7#include <Covellite/Api/Vertex.hpp>
8#include <Covellite/Api/Defines.hpp>
9#include "OpenGLCommon.Texture.hpp"
10#include "Shaders/Shaders.hpp"
11#include "GraphicApi.Constants.hpp"
12
13namespace covellite
14{
15
16namespace api
17{
18
19namespace renderer
20{
21
22inline GLuint glGetProgramId(void)
23{
24 GLint iProgramId = 0;
25 glGetIntegerv(GL_CURRENT_PROGRAM, &iProgramId);
26 return static_cast<GLuint>(iProgramId);
27}
28
29inline void CheckError(const int _Line)
30{
31 const auto Error = glGetError();
32 if (Error != GL_NO_ERROR)
33 {
34 throw EXCEPTION_NO_FILE_LINE(::std::runtime_error) <<
35 _Line << ": error " << Error;
36 }
37}
38
39#define GL_CHECK \
40 CheckError(__LINE__)
41
42template<class>
43class Support; // Not implement!!!
44
45template<>
46class Support<::Camera>
47{
48public:
49 static const GLuint Index = COVELLITE_BUFFER_INDEX_CAMERA;
50
51private:
52 static void Update(
53 const GLuint _ProgramId,
54 const ::Camera & _Matrices,
55 const ::std::string & _BufferName)
56 {
57 const auto MatrixProjectionId =
58 glGetUniformLocation(_ProgramId, (_BufferName + ".Projection").c_str());
59 const auto MatrixViewId =
60 glGetUniformLocation(_ProgramId, (_BufferName + ".View").c_str());
61 const auto MatrixViewInverseId =
62 glGetUniformLocation(_ProgramId, (_BufferName + ".ViewInverse").c_str());
63
64 glUniformMatrix4fv(MatrixProjectionId, 1, GL_FALSE,
65 ::glm::value_ptr(_Matrices.Projection));
66 glUniformMatrix4fv(MatrixViewId, 1, GL_FALSE,
67 ::glm::value_ptr(_Matrices.View));
68 glUniformMatrix4fv(MatrixViewInverseId, 1, GL_FALSE,
69 ::glm::value_ptr(_Matrices.ViewInverse));
70 }
71
72public:
73 static void Update(const GLuint _ProgramId, const ::Camera & _Matrices)
74 {
75 Update(_ProgramId, _Matrices, "MatricesData");
76 Update(_ProgramId, _Matrices, "CameraData");
77 }
78};
79
80template<>
81class Support<::Object>
82{
83public:
84 static const GLuint Index = COVELLITE_BUFFER_INDEX_OBJECT;
85
86public:
87 static void Update(const GLuint _ProgramId, const ::Object & _Object)
88 {
89 const auto MatrixWorldId =
90 glGetUniformLocation(_ProgramId, "ObjectData.World");
91 glUniformMatrix4fv(MatrixWorldId, 1, GL_FALSE,
92 ::glm::value_ptr(_Object.World));
93
94 const auto ExtraId =
95 glGetUniformLocation(_ProgramId, "ObjectData.Extra");
96 glUniform4fv(ExtraId, 1, ::glm::value_ptr(_Object.Extra));
97 }
98};
99
100template<>
101class Support<uint8_t>
102{
103public:
104 static const GLuint Index = COVELLITE_BUFFER_INDEX_USER;
105};
106
107class OpenGLCommonShader::Buffer
108{
109public:
110 inline void Bind(const bool _IsActivate = true) const
111 {
112 glBindBuffer(m_Type, _IsActivate ? m_BufferId : 0);
113 }
114
115 inline void UpdateData(const void * _pData, const size_t _Size) const
116 {
117 glBufferSubData(m_Type, 0, static_cast<GLsizeiptr>(_Size), _pData);
118 }
119
120 inline void UpdateData(const ::std::string & _UniformBufferName,
121 const void * _pData, const size_t _Size) const
122 {
123 const auto ProgramId = glGetProgramId();
124
125 const auto BlockIndex = glGetUniformBlockIndex(
126 ProgramId, _UniformBufferName.c_str());
127
128 // Вероятно, шейдерная программа выкидывает неиспользуемые uniform-буфера,
129 // в результате чего Index становится некорректным и glUniformBlockBinding()
130 // завершается с ошибкой.
131 // При игнорирование ошибки здесь визуально все работает корректно.
132 if (BlockIndex == GL_INVALID_INDEX) return;
133
134 Bind();
135 UpdateData(_pData, _Size);
136 Bind(false);
137
138 glBindBufferBase(m_Type, m_Index, m_BufferId);
139 glUniformBlockBinding(ProgramId, BlockIndex, m_Index);
140 }
141
142 void SetVertexInputData(void) const
143 {
144 // Нужно обязательно проверять валидность идентификаторов, т.к. некоторые
145 // реализации драйверов (не все!) удаляют при компиляции шейдера
146 // объявленные, но не используемые переменные.
147
148 // Явный вызов glVertexAttribDivisor() требуется по той же причине -
149 // из-за удаления в шейдере не используемой переменной вызов этой функции
150 // при использовании инстансинга привяжет смещение к идентификатору,
151 // который в дальнейшем может быть получен здесь.
152
153 const auto ProgramId = glGetProgramId();
154
155 const auto hPosition = static_cast<GLuint>(
156 glGetAttribLocation(ProgramId, "Covellite_VertexPosition"));
157 if (hPosition != -1)
158 {
159 glEnableVertexAttribArray(hPosition);
160 glVertexAttribPointer(hPosition, 4, GL_FLOAT, GL_FALSE,
161 sizeof(::covellite::api::Vertex), (void *)0);
162 glVertexAttribDivisor(hPosition, 0);
163 }
164
165 const auto hTexCoord = static_cast<GLuint>(
166 glGetAttribLocation(ProgramId, "Covellite_VertexTexCoord"));
167 if (hTexCoord != -1)
168 {
169 glEnableVertexAttribArray(hTexCoord);
170 glVertexAttribPointer(hTexCoord, 2, GL_FLOAT, GL_FALSE,
171 sizeof(::covellite::api::Vertex), (void *)(sizeof(float) * 4));
172 glVertexAttribDivisor(hTexCoord, 0);
173 }
174
175 const auto hExtra = static_cast<GLuint>(
176 glGetAttribLocation(ProgramId, "Covellite_VertexExtra"));
177 if (hExtra != -1)
178 {
179 glEnableVertexAttribArray(hExtra);
180 glVertexAttribPointer(hExtra, 4, GL_FLOAT, GL_FALSE,
181 sizeof(::covellite::api::Vertex), (void *)(sizeof(float) * 6));
182 glVertexAttribDivisor(hExtra, 0);
183 }
184 }
185
186 void SetInstanceData(
187 const void * _pData,
188 const size_t _Size,
189 const GLsizei _Stride)
190 {
191 using AttributeTypes_t = ::alicorn::extension::std::fast::unordered_map<
192 ::std::string, ::std::pair<GLint, GLenum>>;
193
194 constexpr auto BlockSize = sizeof(float) * 4;
195 const auto BlockCount = _Stride / BlockSize;
196
197 Bind(true);
198 UpdateData(_pData, _Size);
199
200 const auto ProgramId = glGetProgramId();
201
202 const auto GetAttributeTypes = [&](void) -> AttributeTypes_t
203 {
204 // С одной стороны, список атрибутов достаточно формировать один раз
205 // для каждой шейдерной программы, с другой стороны - индексы могут быть
206 // изменены при помощи функции glBindAttribLocation().
207
208 constexpr GLsizei NameBufferSize = 255;
209 GLsizei NameLength = 0;
210 GLint ValueSize = 0;
211 GLchar ValueName[NameBufferSize] = { 0 };
212
213 GLint AttributeCount = 0;
214 glGetProgramiv(ProgramId, GL_ACTIVE_ATTRIBUTES, &AttributeCount);
215
216 AttributeTypes_t Result;
217
218 for (GLuint i = 0; i < static_cast<GLuint>(AttributeCount); i++)
219 {
220 auto iType = static_cast<GLenum>(-1);
221 glGetActiveAttrib(ProgramId, i, NameBufferSize, &NameLength,
222 &ValueSize, &iType, ValueName);
223
224 Result[ValueName] = { i, // Индексы - для отладочных целей
225 (iType == GL_FLOAT_VEC4) ? GL_FLOAT :
226 (iType == GL_INT_VEC4) ? GL_INT : iType };
227 }
228
229 return Result;
230 };
231
232 // Работа через список всех атрибутов понадобилась из-за того, что функция
233 // glGetActiveAttrib() в Windows версии ожидает hInstance, а в Android
234 // версии - индекс атрибута (в Android версии при компиляции шейдера
235 // удаляются все неиспользуемые переменные и hInstance и индекс не совпадают).
236 auto AttributeTypes = GetAttributeTypes();
237
238 for (::std::size_t i = 0; i < BlockCount; i++)
239 {
240 const auto Name = "iValue" + ::std::to_string(i + 1);
241
242 const auto hInstance = static_cast<GLuint>(
243 glGetAttribLocation(ProgramId, Name.c_str()));
244 if (hInstance == -1) continue;
245
246 glEnableVertexAttribArray(hInstance);
247 glVertexAttribPointer(hInstance, 4, AttributeTypes[Name].second,
248 GL_FALSE, _Stride, (void*)(BlockSize * i));
249 glVertexAttribDivisor(hInstance, 1);
250 }
251
252 Bind(false);
253 }
254
255private:
256 const GLenum m_Type;
257 const GLuint m_Index;
258 GLuint m_BufferId;
259
260public:
261 Buffer(
262 const GLenum _Type,
263 const void * _pData,
264 const ::std::size_t _Size,
265 const GLenum _Usage,
266 const GLuint _Index = static_cast<GLuint>(-1)) :
267 m_Type(_Type),
268 m_Index(_Index)
269 {
270 glGenBuffers(1, &m_BufferId);
271 Bind();
272 glBufferData(m_Type, static_cast<GLsizeiptr>(_Size), _pData, _Usage);
273 Bind(false);
274
275 const auto Error = glGetError();
276 if (Error != GL_NO_ERROR)
277 {
278 throw STD_EXCEPTION << "Create buffer error: " << Error;
279 }
280 }
281
282 template<class T>
283 Buffer(const T * _pData, const ::std::size_t _Size) :
284 Buffer(GL_UNIFORM_BUFFER, _pData, _Size, GL_DYNAMIC_DRAW, Support<T>::Index)
285 {
286
287 }
288
289 Buffer(const Buffer &) = delete;
290 Buffer(Buffer &&) = delete;
291 Buffer & operator= (const Buffer &) = delete;
292 Buffer & operator= (Buffer &&) = delete;
293
294 ~Buffer(void) noexcept
295 {
296 glDeleteBuffers(1, &m_BufferId);
297 }
298};
299
300template<class T>
301class OpenGLCommonShader::ConstantBuffer :
302 public GraphicApi::Constants::Data<T>
303{
304public:
305 void Update(void) const override
306 {
307 const auto ProgramId = glGetProgramId();
308
309 Support<T>::Update(ProgramId, Constants::Data<T>::m_Data);
310
311 // 21 Сентябрь 2019 11:58 (unicornum.verum@gmail.com)
312 TODO("Использование uniform-буфера");
313
314 //static const char * Name[] =
315 //{
316 // "cbCameraData",
317 // "cbFogData",
318 // "cbObjectData",
319 // "cbUserData",
320 // "cbMatricesData",
321 // "cbLightsData",
322 //};
323
324 //const auto & Data = Constants::Data<T>::m_Data;
325
326 //if (m_pBuffer == nullptr)
327 //{
328 // m_pBuffer = ::std::make_shared<OpenGLCommonShader::Buffer>(
329 // &Data, sizeof(T));
330 //}
331
332 //m_pBuffer->Update(Name[Support<T>::Index], &Data, sizeof(T));
333 }
334
335private:
336 //mutable ::std::shared_ptr<OpenGLCommonShader::Buffer> m_pBuffer;
337};
338
339OpenGLCommonShader::OpenGLCommonShader(
340 const Data_t & _Data,
341 const String_t & _PreVersion,
342 const ::std::string & _ShaderHeader) :
343 OpenGLCommon{ _Data, _PreVersion },
344 m_pPrograms{ ::std::make_shared<Programs>(_ShaderHeader) }
345{
346 MakeConstants<ConstantBuffer>();
347}
348
349auto OpenGLCommonShader::GetUsingApi(void) const -> String_t /*override*/
350{
351 const auto UsingApi = OpenGLCommon::GetUsingApi();
352
353 LOGGER(Info) << "GL_VENDOR: " <<
354 (const char *)glGetString(GL_VENDOR);
355 LOGGER(Info) << "GL_RENDERER: " <<
356 (const char *)glGetString(GL_RENDERER);
357 LOGGER(Info) << "GL_SHADING_LANGUAGE_VERSION: " <<
358 (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
359
360 GLint ExtensionCount = 0;
361 glGetIntegerv(GL_NUM_EXTENSIONS, &ExtensionCount);
362
363 for (GLint i = 0; i < ExtensionCount; i++)
364 {
365 LOGGER(Info) << "GL_EXTENSIONS: " <<
366 (const char *)glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(i));
367 }
368
369 return UsingApi;
370}
371
372void OpenGLCommonShader::PresentFrame(void) /*override*/
373{
374 OpenGLCommon::PresentFrame();
375
376 // При отложенной загрузке первый вызов Present() произойдет для пустой
377 // очереди рендеринга, что породит ошибку, которая будет детектирована
378 // позже, при создании какого-то объекта.
379 while (glGetError() != GL_NO_ERROR) {}
380}
381
382auto OpenGLCommonShader::CreateCamera(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
383{
384 const auto CameraRender = (_pComponent->Kind == uT("Perspective")) ?
385 GetCameraPerspective(_pComponent) : GetCameraOrthographic(_pComponent);
386
387 const auto CameraId = _pComponent->Id;
388
389 return [=](void)
390 {
391 CameraRender();
392 };
393}
394
395class FrameBuffer
396{
397public:
398 inline void Bind(void) const
399 {
400 GLint CurrentFrameBufferId = 0;
401 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &CurrentFrameBufferId);
402 m_CurrentFrameBufferId = static_cast<GLuint>(CurrentFrameBufferId);
403
404 glBindFramebuffer(GL_FRAMEBUFFER, m_Id);
405 }
406
407 inline void Unbind(void) const
408 {
409 glBindFramebuffer(GL_FRAMEBUFFER, m_CurrentFrameBufferId);
410 }
411
412private:
413 GLuint m_Id = 0;
414 mutable GLuint m_CurrentFrameBufferId = 0;
415
416public:
417 FrameBuffer(void) noexcept
418 {
419 glGenFramebuffers(1, &m_Id);
420 }
421 FrameBuffer(const FrameBuffer &) = delete;
422 FrameBuffer(FrameBuffer &&) = delete;
423 FrameBuffer & operator= (const FrameBuffer &) = delete;
424 FrameBuffer & operator= (FrameBuffer &&) = delete;
425 ~FrameBuffer(void) noexcept
426 {
427 glDeleteFramebuffers(1, &m_Id);
428 }
429};
430
431auto OpenGLCommonShader::CreateBkSurface(
432 const ComponentPtr_t & _pComponent) -> Render_t /*override*/
433{
434 // !!!std::tuple не компилируется на Android!!!
435 using Size_t = ::std::pair<GLint, GLint>;
436 using fnBkSurfaceSize_t = ::std::function<Size_t(void)>;
437
438 const auto pBkSurface = _pComponent;
439
440 const fnBkSurfaceSize_t GetBkSurfaceSize = [=](void)
441 {
442 GLint Viewport[4] = { 0 };
443 glGetIntegerv(GL_VIEWPORT, Viewport);
444
445 const int Width = static_cast<int>(Viewport[2]);
446 const int Height = static_cast<int>(Viewport[3]);
447
448 (*pBkSurface)[uT("width")] = Width;
449 (*pBkSurface)[uT("height")] = Height;
450
451 return Size_t{ static_cast<GLint>(Width), static_cast<GLint>(Height) };
452 };
453
454 const auto Size = GetBkSurfaceSize();
455 const auto Width = Size.first;
456 const auto Height = Size.second;
457
458 const auto pFrameBuffer = ::std::make_shared<FrameBuffer>();
459 pFrameBuffer->Bind();
460
461 ::std::vector<GLenum> AttachmentIndexes;
462 ::std::vector<::std::pair<ComponentPtr_t, Texture::Ptr_t>> Textures;
463
464 const auto DoDataTexture = [&](const ComponentPtr_t & _pDataTexture)
465 {
466 (*_pDataTexture)[uT("width")] = Width;
467 (*_pDataTexture)[uT("height")] = Height;
468
469 const Component::Texture TextureData{ *_pDataTexture, uT("diffuse") };
470
471 const auto pTexture = ::std::make_shared<Texture>(TextureData);
472 Textures.push_back({ _pDataTexture, pTexture });
473
474 if (pTexture->m_Format != GL_DEPTH_COMPONENT)
475 {
476 const auto Attachment = GL_COLOR_ATTACHMENT0 +
477 static_cast<unsigned int>(AttachmentIndexes.size());
478 AttachmentIndexes.push_back(Attachment);
479 glFramebufferTexture2D(GL_FRAMEBUFFER, Attachment, GL_TEXTURE_2D,
480 pTexture->m_TextureId, 0);
481 }
482 else
483 {
484 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
485 GL_TEXTURE_2D, pTexture->m_TextureId, 0);
486 }
487
488 (*_pDataTexture)[uT("entity")].Default(pTexture);
489 };
490
491 CapturingServiceComponent::Process(_pComponent,
492 { { uT("Texture"), DoDataTexture } });
493
494 const auto FramebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
495 pFrameBuffer->Unbind();
496
497 if (FramebufferStatus != GL_FRAMEBUFFER_COMPLETE)
498 {
499 throw STD_EXCEPTION << "Create Framebuffer fail: " << _pComponent->Id;
500 }
501
502 return [=](void)
503 {
504 const auto [Width, Height] = GetBkSurfaceSize();
505
506 if (m_IsResizeWindow)
507 {
508 for (const auto & Texture : Textures)
509 {
510 (*Texture.first)[uT("width")] = Width;
511 (*Texture.first)[uT("height")] = Height;
512 Texture.second->MakeContent(Width, Height, nullptr);
513 }
514 }
515
516 pFrameBuffer->Bind();
517 glDrawBuffers(static_cast<GLsizei>(AttachmentIndexes.size()),
518 AttachmentIndexes.data());
519 };
520}
521
522auto OpenGLCommonShader::CreateState(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
523{
524 if (_pComponent->Kind == uT("AlphaTest")) return nullptr;
525
526 return OpenGLCommon::CreateState(_pComponent);
527}
528
529auto OpenGLCommonShader::CreateTexture(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
530{
531 using BufferMapper_t = cbBufferMap_t<const void>;
532
533 const auto pTextureDataComponent = CapturingServiceComponent::Get(_pComponent,
534 { { uT("Texture"), _pComponent } })[0];
535
536 const auto pTextureData =
537 ::std::make_shared<Component::Texture>(*pTextureDataComponent, uT("diffuse"));
538
539 ::std::function<GLint(void)> GetTexMinFilter =
540 [=](void) { return m_TexParameters.MinFilter; };
541
542 Texture::Ptr_t pTexture =
543 (*pTextureDataComponent)[uT("entity")].Default(Texture::Ptr_t{});
544 if (pTexture == nullptr)
545 {
546 pTexture = ::std::make_shared<Texture>(*pTextureData);
547
548 if (pTextureData->IsUsingMipmapping)
549 {
550 GetTexMinFilter = [](void) { return GL_LINEAR_MIPMAP_LINEAR; };
551
552 pTexture->Bind();
553 glGenerateMipmap(GL_TEXTURE_2D);
554 pTexture->Bind(false);
555 }
556 }
557 else
558 {
559 (*pTextureDataComponent)[uT("entity")] = Texture::Ptr_t{};
560 }
561
562 const Render_t TextureRender = [=](void)
563 {
564 const auto Index = pTexture->m_Destination.first;
565
566 glActiveTexture(GL_TEXTURE0 + Index);
567 pTexture->Bind();
568
569 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GetTexMinFilter());
570 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_TexParameters.MagFilter);
571 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_TexParameters.WrapS);
572 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_TexParameters.WrapT);
573
574 const auto ProgramId = glGetProgramId();
575
576 const auto LocationId = glGetUniformLocation(ProgramId,
577 pTexture->m_Destination.second.c_str());
578
579 // -1 означает, что в шейдере такой текстуры нет, но glGetError() при этом
580 // не возвращает ошибку, поэтому просто игнорируем ситуацию.
581 if (LocationId == -1) return;
582
583 glUniform1i(LocationId, Index);
584 };
585
586 if (!(*pTextureDataComponent)[uT("mapper")].IsType<const BufferMapper_t &>())
587 {
588 return TextureRender;
589 }
590
591 const BufferMapper_t cbBufferMapper =
592 (*pTextureDataComponent)[uT("mapper")].Default(BufferMapper_t{});
593 const auto pFrameBuffer = ::std::make_shared<FrameBuffer>();
594
595 return [=](void)
596 {
597 if (cbBufferMapper(nullptr))
598 {
599 pFrameBuffer->Bind();
600 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
601 GL_TEXTURE_2D, pTexture->m_TextureId, 0);
602
603 auto * pData = reinterpret_cast<uint32_t *>(pTexture->m_ReadCopyData.data());
604
605 glReadPixels(0, 0, pTextureData->Width, pTextureData->Height, GL_RGBA,
606 GL_UNSIGNED_BYTE, pData);
607
608 // Изображение в текстуре OpenGL перевернуто по Y, поэтому...
609 for (int y = 0; y < pTextureData->Height / 2; y++)
610 {
611 auto * pLineUp =
612 pData + (static_cast<size_t>(y) * pTextureData->Width);
613 auto * pLineDown =
614 pData + ((static_cast<size_t>(pTextureData->Height) - y - 1) * pTextureData->Width);
615
616 for (int x = 0; x < pTextureData->Width; x++)
617 {
618 auto & Up = *(pLineUp + x);
619 auto & Down = *(pLineDown + x);
620
621 ::std::swap(Up, Down);
622 }
623 }
624
625 cbBufferMapper(pData);
626 pFrameBuffer->Unbind();
627 }
628
629 TextureRender();
630 };
631}
632
633auto OpenGLCommonShader::CreateTextureArray(
634 const ComponentPtr_t & _pComponent) -> Render_t /*override*/
635{
636 const auto pTextureArrayData = CapturingServiceComponent::Get(_pComponent,
637 { { uT("TextureArray"), _pComponent } })[0];
638
639 const Component::Texture TextureData(*pTextureArrayData, uT("diffuse"));
640 auto pTexture = ::std::make_shared<Texture>(TextureData, true);
641
642 ::std::function<GLint(void)> GetTexMinFilter =
643 [=](void) { return m_TexParameters.MinFilter; } ;
644 if (TextureData.IsUsingMipmapping) GetTexMinFilter =
645 [](void) { return GL_LINEAR_MIPMAP_LINEAR; };
646
647 return [=](void)
648 {
649 const auto Index = pTexture->m_Destination.first;
650
651 glActiveTexture(GL_TEXTURE0 + Index);
652 pTexture->Bind();
653
654 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GetTexMinFilter());
655 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, m_TexParameters.MagFilter);
656 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, m_TexParameters.WrapS);
657 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, m_TexParameters.WrapT);
658
659 const auto ProgramId = glGetProgramId();
660
661 const auto LocationId = glGetUniformLocation(ProgramId,
662 pTexture->m_Destination.second.c_str());
663
664 // -1 означает, что в шейдере такой текстуры нет, но glGetError() при этом
665 // не возвращает ошибку, поэтому просто игнорируем ситуацию.
666 if (LocationId == -1) return;
667
668 glUniform1i(LocationId, Index);
669 };
670}
671
672class OpenGLCommonShader::Programs final
673{
674 class Program final
675 {
676 public:
677 void Link(const GLuint _VsShaderId, const GLuint & _PsShaderId)
678 {
679 glAttachShader(Id, _VsShaderId);
680 glAttachShader(Id, _PsShaderId);
681 glLinkProgram(Id);
682
683 GLint Result = GL_FALSE;
684 glGetProgramiv(Id, GL_LINK_STATUS, &Result);
685 if (Result == GL_TRUE)
686 {
687 Use = [=](void) { glUseProgram(Id); };
688 }
689 else
690 {
691 Use = [](void) {};
692
693 char InfoLog[512] = { 0 };
694 glGetProgramInfoLog(Id, sizeof(InfoLog), NULL, InfoLog);
695
696 LOGGER(Warning) << "Link program fail: " << InfoLog;
697 }
698 }
699
700 ::std::function<void(void)> Use;
701
702 private:
703 const GLuint Id;
704
705 public:
706 Program(void) noexcept :
707 Id{ glCreateProgram() }
708 {
709 }
710 Program(const Program &) = delete;
711 Program(Program &&) = delete;
712 Program & operator= (const Program &) = delete;
713 Program & operator= (Program &&) = delete;
714 ~Program(void) noexcept
715 {
716 glDeleteProgram(Id);
717 }
718 };
719
720 class Shader final
721 {
722 public:
723 void Compile(void)
724 {
725 glCompileShader(Id);
726
727 GLint Result = GL_FALSE;
728 glGetShaderiv(Id, GL_COMPILE_STATUS, &Result);
729 if (Result == GL_FALSE)
730 {
731 // Так делать правильно, но это не работает на Android'e:
732 //GLint InfoLogLenght = 0;
733 //glGetShaderiv(Id, GL_INFO_LOG_LENGTH, &InfoLogLenght);
734 //const auto Size = static_cast<::std::size_t>(InfoLogLenght + 1);
735 //::std::vector<GLchar> InfoLog(Size, (GLchar)0x00);
736
737 ::std::vector<GLchar> InfoLog(512, 0x00);
738 glGetShaderInfoLog(Id, InfoLog.size(), nullptr, InfoLog.data());
739
740 throw STD_EXCEPTION << "Compile shader fail "
741 << "[header line: " << GetHeaderLines(m_Header) << "]: "
742 << InfoLog.data();
743 };
744 }
745
746 private:
747 static ::std::size_t GetHeaderLines(const ::std::string & _Header)
748 {
749 ::std::size_t Result = 0;
750
751 auto itPosition = _Header.cbegin();
752 while (true)
753 {
754 itPosition = ::std::find(itPosition, _Header.cend(), '\n');
755 if (itPosition == _Header.cend()) break;
756
757 ++itPosition;
758 Result++;
759 }
760
761 return Result;
762 }
763
764 public:
765 Programs & m_Programs;
766 const GLenum Type;
767 const GLuint Id;
768 const ::std::string m_Header;
769
770 public:
771 Shader(Programs & _Programs, const GLenum _Type,
772 const GLchar * _Header, const GLchar * _Body) :
773 m_Programs{ _Programs },
774 Type{ _Type },
775 Id{ glCreateShader(_Type) },
776 m_Header(_Header)
777 {
778 const auto FullShaderBody = ::std::string{ _Header } +_Body;
779 auto pFullShaderBody = FullShaderBody.c_str();
780 glShaderSource(Id, 1, &pFullShaderBody, nullptr);
781 }
782 Shader(const Shader &) = delete;
783 Shader(Shader &&) = delete;
784 Shader & operator= (const Shader &) = delete;
785 Shader & operator= (Shader &&) = delete;
786 ~Shader(void) noexcept
787 {
788 m_Programs.Clear(Id);
789 glDeleteShader(Id);
790 }
791 };
792
793 using ProgramPtr_t = ::std::shared_ptr<Program>;
794 using Programs_t = ::std::map<GLuint, ::std::map<GLuint, ProgramPtr_t>>;
795 using ShaderPtr_t = ::std::shared_ptr<Shader>;
796
797public:
798 ShaderPtr_t MakeVertex(const Component::Shader & _ShaderData)
799 {
800 using namespace ::alicorn::extension::std;
801
802 const auto HeaderShaderText =
803 ::Predefined +
804 ::Data +
805 _ShaderData.GetInstanceInput(::Input);
806
807 const auto BodyShaderText = _ShaderData.Data;
808
809 return ::std::make_shared<Shader>(*this, GL_VERTEX_SHADER,
810 (m_ShaderHeader +
811 "#define COVELLITE_SHADER_VERTEX\r\n" +
812 ::std::string{ ::std::begin(HeaderShaderText), ::std::end(HeaderShaderText) }).c_str(),
813 (::std::string{ ::std::begin(BodyShaderText), ::std::end(BodyShaderText) } +
814 "out Pixel PixelValue;\r\n"
815 "void main()\r\n"
816 "{\r\n"
817 " Vertex InputData;\r\n"
818 " InputData.Position = Covellite_VertexPosition;\r\n"
819 " InputData.TexCoord = Covellite_VertexTexCoord;\r\n"
820 " InputData.Extra = Covellite_VertexExtra;\r\n" +
821 _ShaderData.GetInstanceCopyData() +
822 " PixelValue = " + _ShaderData.Entry + "(InputData);\r\n"
823 " gl_Position = PixelValue.ScreenPos;\r\n"
824 "}\r\n").c_str());
825 }
826
827 ShaderPtr_t MakePixel(const Component::Shader & _ShaderData)
828 {
829 using namespace ::alicorn::extension::std;
830
831 const auto HeaderShaderText = ::Predefined + ::Data + ::Input;
832 const auto BodyShaderText = ::std::string{
833 _ShaderData.Data.cbegin(), _ShaderData.Data.cend() };
834
835 ::std::string Main;
836
837 if (_ShaderData.ReturnType == "float4" ||
838 _ShaderData.ReturnType == "vec4")
839 {
840 Main =
841 "out vec4 Covellite_OutPixelColor;\r\n"
842 "void main()\r\n"
843 "{\r\n"
844 " Covellite_OutPixelColor = " + _ShaderData.Entry + "(PixelValue);\r\n"
845 "}\r\n";
846 }
847 else if (_ShaderData.ReturnType == "void")
848 {
849 Main =
850 "void main()\r\n"
851 "{\r\n"
852 " " + _ShaderData.Entry + "(PixelValue);\r\n"
853 "}\r\n";
854 }
855 else
856 {
857 Main =
858 "void main()\r\n"
859 "{\r\n"
860 " Covellite_MultiOutPixelColor = " + _ShaderData.Entry + "(PixelValue).Target;\r\n"
861 "}\r\n";
862 }
863
864 return ::std::make_shared<Shader>(*this, GL_FRAGMENT_SHADER,
865 (m_ShaderHeader +
866 "#define COVELLITE_SHADER_PIXEL\r\n" +
867 ::std::string{ ::std::begin(HeaderShaderText), ::std::end(HeaderShaderText) }).c_str(),
868 (BodyShaderText +
869 "in Pixel PixelValue;\r\n" +
870 Main).c_str());
871 }
872
873 void Activate(const ShaderPtr_t & _pShader)
874 {
875 if (_pShader->Type == GL_VERTEX_SHADER) m_VsShaderId = _pShader->Id;
876 if (_pShader->Type == GL_FRAGMENT_SHADER) m_PsShaderId = _pShader->Id;
877 if (m_VsShaderId == InvalidId || m_PsShaderId == InvalidId) return;
878
879 auto & pProgram = m_Programs[m_VsShaderId][m_PsShaderId];
880
881 if (pProgram == nullptr)
882 {
883 pProgram = ::std::make_shared<Program>();
884 pProgram->Link(m_VsShaderId, m_PsShaderId);
885 }
886
887 pProgram->Use();
888 }
889
890 void Clear(const GLuint _ShaderId)
891 {
892 for (auto & VertexPrograms : m_Programs)
893 {
894 if (VertexPrograms.first == _ShaderId)
895 {
896 for (auto & PixelPrograms : VertexPrograms.second)
897 {
898 PixelPrograms.second.reset();
899 }
900
901 return;
902 }
903
904 for (auto & PixelPrograms : VertexPrograms.second)
905 {
906 if (PixelPrograms.first == _ShaderId)
907 {
908 PixelPrograms.second.reset();
909 }
910 }
911 }
912 }
913
914private:
915 const ::std::string m_ShaderHeader;
916 const GLuint InvalidId = static_cast<GLuint>(-1);
917 GLuint m_VsShaderId = InvalidId;
918 GLuint m_PsShaderId = InvalidId;
919 const uint8_t Align[4] = { 0 };
920 Programs_t m_Programs;
921
922public:
923 explicit Programs(const ::std::string & _ShaderHeader) :
924 m_ShaderHeader(_ShaderHeader + "#define COVELLITE_SHADER_GLSL\r\n")
925 {
926
927 }
928 Programs(const Programs &) = delete;
929 Programs(Programs &&) = delete;
930 Programs & operator= (const Programs &) = delete;
931 Programs & operator= (Programs &&) = delete;
932 ~Programs(void) = default;
933};
934
935auto OpenGLCommonShader::CreateShader(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
936{
937 const auto pShaderDataComponent = CapturingServiceComponent::Get(_pComponent,
938 { { uT("Shader"), _pComponent } })[0];
939
940 const Component::Shader ShaderData{ *pShaderDataComponent, ::Default };
941
942 if (ShaderData.Kind == uT("Vertex"))
943 {
944 const auto pShader = m_pPrograms->MakeVertex(ShaderData);
945 pShader->Compile();
946
947 return [=](void)
948 {
949 m_pPrograms->Activate(pShader);
950 };
951 }
952 else if (ShaderData.Kind == uT("Pixel"))
953 {
954 const auto pShader = m_pPrograms->MakePixel(ShaderData);
955 pShader->Compile();
956
957 return [=](void)
958 {
959 m_pPrograms->Activate(pShader);
960
961# ifndef TEST_CALL_IF
962# define TEST_CALL_IF(n)
963# endif
964
965 TEST_CALL_IF(1) m_pConstants->Update<::Camera>();
966
967# undef TEST_CALL_IF
968 };
969 }
970
971 return nullptr;
972}
973
974auto OpenGLCommonShader::CreateBuffer(const ComponentPtr_t & _pBuffer) -> Render_t /*override*/
975{
976 const auto pBufferData = CapturingServiceComponent::Get(_pBuffer,
977 { { uT("Buffer"), _pBuffer } })[0];
978
979 auto CreateConstantUserBuffer = [&](void) -> Render_t
980 {
981 using Type_t = cbBufferMap_t<void>;
982
983 if (!(*_pBuffer)[uT("mapper")].IsType<const Type_t &>())
984 {
985 throw STD_EXCEPTION << "Unexpected buffer format [" <<
986 "id: " << _pBuffer->Id << ", " <<
987 "type: " << _pBuffer->Type << ", " <<
988 "kind: " << _pBuffer->Kind << "].";
989 }
990
991 const Type_t cbBufferMapper =
992 (*_pBuffer)[uT("mapper")].Default(Type_t{});
993 if (!cbBufferMapper)
994 {
995 throw STD_EXCEPTION << "Unexpected empty mapper: " << _pBuffer->Id;
996 }
997
998 const ::std::size_t BufferSize =
999 (*_pBuffer)[uT("size")].Default((::std::size_t)0);
1000 if (BufferSize == 0)
1001 {
1002 throw STD_EXCEPTION << "Unexpected zero size: " << _pBuffer->Id;
1003 }
1004
1005 const ::std::string cbName =
1006 (*_pBuffer)[uT("name")].Default(::std::string{ "cbUserData" });
1007
1008 const auto pData =
1009 ::std::make_shared<BinaryData_t>(BufferSize, (uint8_t)0x00);
1010 const auto pBuffer =
1011 ::std::make_shared<Buffer>(pData->data(), pData->size());
1012
1013 return [=](void)
1014 {
1015 cbBufferMapper(pData->data());
1016 pBuffer->UpdateData(cbName, pData->data(), pData->size());
1017 };
1018 };
1019
1020 const auto CreateVertexBuffer = [&](void) -> Render_t
1021 {
1022 using Type_t = ::covellite::api::Vertex;
1023 using BufferMapper_t = cbBufferMap_t<Type_t>;
1024
1025 if (!(*pBufferData)[uT("content")].IsType<Buffer_t<Type_t>>())
1026 {
1027 return CreateConstantUserBuffer();
1028 }
1029
1030 const Component::Buffer<Type_t> Info{ *pBufferData };
1031
1032 const BufferMapper_t & cbBufferMapper =
1033 (*_pBuffer)[uT("mapper")].Default(BufferMapper_t{});
1034
1035 if (cbBufferMapper == nullptr)
1036 {
1037 const auto pBuffer = ::std::make_shared<Buffer>(GL_ARRAY_BUFFER,
1038 Info.Data.data(), Info.Data.size() * sizeof(Type_t), GL_STATIC_DRAW);
1039
1040 return [=](void)
1041 {
1042 pBuffer->Bind();
1043 pBuffer->SetVertexInputData();
1044 pBuffer->Bind(false);
1045 };
1046 }
1047
1048 const auto pBuffer = ::std::make_shared<Buffer>(GL_ARRAY_BUFFER,
1049 Info.Data.data(), Info.Data.size() * sizeof(Type_t), GL_DYNAMIC_DRAW);
1050
1051 const auto pData = ::std::make_shared<Buffer_t<Type_t>>(Info.Data);
1052
1053 return [=](void)
1054 {
1055 pBuffer->Bind();
1056
1057 const auto IsDirty = cbBufferMapper(nullptr);
1058 if (IsDirty)
1059 {
1060 cbBufferMapper(pData->data());
1061
1062 pBuffer->UpdateData(pData->data(),
1063 static_cast<size_t>(pData->size() * sizeof(Type_t)));
1064 }
1065
1066 pBuffer->SetVertexInputData();
1067 pBuffer->Bind(false);
1068 };
1069 };
1070
1071 return CreateVertexBuffer();
1072}
1073
1074auto OpenGLCommonShader::CreateTransform(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
1075{
1076 using TransformRender_t = ::std::function<void(void)>;
1077
1078 const auto GetPreRenderDefaultGeometry = [&](void) -> TransformRender_t
1079 {
1080 const auto TransformRender = GetPreRenderGeometry(_pComponent);
1081
1082 return [=](void)
1083 {
1084 auto & World = m_pConstants->Get<::Object>().World;
1085 World = ::glm::identity<::glm::mat4>();
1086 TransformRender(World);
1087 World = ::glm::transpose(World);
1088 };
1089 };
1090
1091 const auto GetPreRenderStaticGeometry = [&](void) -> TransformRender_t
1092 {
1093 ::glm::mat4 World = ::glm::identity<::glm::mat4>();
1094 GetPreRenderGeometry(_pComponent)(World);
1095 World = ::glm::transpose(World);
1096
1097 return [=](void)
1098 {
1099 m_pConstants->Get<::Object>().World = World;
1100 };
1101 };
1102
1103 const auto GetPreRenderBillboardGeometry = [&](void) -> TransformRender_t
1104 {
1105 const auto TransformRender =
1106 OpenGLCommonShader::GetPreRenderBillboardGeometry(_pComponent);
1107
1108 return [=](void)
1109 {
1110 auto & World = m_pConstants->Get<::Object>().World;
1111 World = m_pConstants->Get<::Camera>().View;
1112 TransformRender(World);
1113 World = ::glm::transpose(World);
1114 };
1115 };
1116
1117 // 17 Сентябрь 2019 12:58 (unicornum.verum@gmail.com)
1118 TODO("Тест Transform.Static не проверяет, что матрица меняется у РАЗНЫХ объектов");
1119
1120 // cppcheck-suppress internalAstError
1121 const auto TransformRender =
1122 (_pComponent->Kind == uT("Unknown")) ? GetPreRenderDefaultGeometry() :
1123 (_pComponent->Kind == uT("Static")) ? GetPreRenderStaticGeometry() :
1124 (_pComponent->Kind == uT("Billboard")) ? GetPreRenderBillboardGeometry() :
1125 throw STD_EXCEPTION << "Unexpected transform component: " <<
1126 " [id=" << _pComponent->Id << ", kind=" << _pComponent->Kind << "].";
1127
1128 return [=](void)
1129 {
1130 m_pConstants->Get<::Object>().Extra =
1131 (*_pComponent)[uT("extra")].Default(::glm::vec4{});
1132
1133 TransformRender();
1134 m_pConstants->Update<::Object>();
1135 };
1136}
1137
1138auto OpenGLCommonShader::CreatePresentBuffer(const ComponentPtr_t & _pComponent) -> Render_t /*override*/
1139{
1140 using BufferMapperMaxCount_t = ::std::function<bool(void *)>;
1141 using BufferMapperChangeCount_t = ::std::function<bool(void *, ::std::size_t &)>;
1142
1143 ComponentPtr_t pIndexBufferData = _pComponent;
1144 ComponentPtr_t pInstanceBufferData = nullptr;
1145
1146 const auto SaveBuffer = [&](const ComponentPtr_t & _pBufferData)
1147 {
1148 if ((*_pBufferData)[uT("content")].IsType<Buffer_t<int>>())
1149 {
1150 pIndexBufferData = _pBufferData;
1151 }
1152 else if ((*_pBufferData)[uT("mapper")].IsType<const BufferMapperMaxCount_t &>())
1153 {
1154 pInstanceBufferData = _pBufferData;
1155 }
1156 else if ((*_pBufferData)[uT("mapper")].IsType<const BufferMapperChangeCount_t &>())
1157 {
1158 pInstanceBufferData = _pBufferData;
1159 }
1160 else
1161 {
1162 throw STD_EXCEPTION << "Unexpected Presend data component: id = " <<
1163 _pComponent->Id;
1164 }
1165 };
1166
1167 CapturingServiceComponent::Process(_pComponent,
1168 {
1169 { uT("Buffer"), SaveBuffer },
1170 });
1171
1172 const Component::Buffer<int> IndexBufferData{ *pIndexBufferData };
1173
1174 const auto pIndexBuffer = ::std::make_shared<Buffer>(GL_ELEMENT_ARRAY_BUFFER,
1175 IndexBufferData.Data.data(), IndexBufferData.Data.size() * sizeof(int), GL_STATIC_DRAW);
1176 const auto IndexCount = static_cast<GLsizei>(IndexBufferData.Data.size());
1177
1178 if (pInstanceBufferData == nullptr)
1179 {
1180 return [=](void)
1181 {
1182 pIndexBuffer->Bind();
1183 glDrawElements(GL_TRIANGLES, IndexCount, GL_UNSIGNED_INT, nullptr);
1184 pIndexBuffer->Bind(false);
1185 };
1186 }
1187
1188 const ::std::size_t BufferSize = (*pInstanceBufferData)[uT("size")];
1189 if (BufferSize % 16 != 0)
1190 {
1191 throw STD_EXCEPTION << _pComponent->Id << ": size % 16 != 0";
1192 }
1193
1194 const ::std::size_t MaxInstanceCount = (*pInstanceBufferData)[uT("count")];
1195 if (BufferSize % MaxInstanceCount != 0)
1196 {
1197 throw STD_EXCEPTION << _pComponent->Id << ": size % count != 0";
1198 }
1199
1200 const auto Stride = static_cast<GLsizei>(BufferSize / MaxInstanceCount);
1201
1202 const auto pData =
1203 ::std::make_shared<BinaryData_t>(BufferSize, (uint8_t)0x00);
1204 const auto pInstanceBuffer = ::std::make_shared<Buffer>(GL_ARRAY_BUFFER,
1205 nullptr, BufferSize, GL_DYNAMIC_DRAW);
1206
1207 if ((*pInstanceBufferData)[uT("mapper")].IsType<BufferMapperMaxCount_t>())
1208 {
1209 const BufferMapperMaxCount_t cbBufferMapper =
1210 (*pInstanceBufferData)[uT("mapper")];
1211
1212 return [=](void)
1213 {
1214 const auto IsDirty = cbBufferMapper(nullptr);
1215 if (IsDirty)
1216 {
1217 cbBufferMapper(pData->data());
1218 pInstanceBuffer->SetInstanceData(pData->data(), pData->size(), Stride);
1219 }
1220
1221 pIndexBuffer->Bind();
1222 glDrawElementsInstanced(GL_TRIANGLES, IndexCount, GL_UNSIGNED_INT, nullptr,
1223 static_cast<GLsizei>(MaxInstanceCount));
1224 pIndexBuffer->Bind(false);
1225 };
1226 }
1227
1228 const BufferMapperChangeCount_t cbBufferMapper =
1229 (*pInstanceBufferData)[uT("mapper")];
1230
1231 return [=](void)
1232 {
1233 auto InstanceCount = MaxInstanceCount;
1234
1235 const auto IsDirty = cbBufferMapper(nullptr, InstanceCount);
1236 if (IsDirty)
1237 {
1238 cbBufferMapper(pData->data(), InstanceCount);
1239 pInstanceBuffer->SetInstanceData(pData->data(), pData->size(), Stride);
1240 }
1241
1242 InstanceCount = ::std::min(InstanceCount, MaxInstanceCount);
1243
1244 pIndexBuffer->Bind();
1245 glDrawElementsInstanced(GL_TRIANGLES, IndexCount, GL_UNSIGNED_INT, nullptr,
1246 static_cast<GLsizei>(InstanceCount));
1247 pIndexBuffer->Bind(false);
1248 };
1249}
1250
1251auto OpenGLCommonShader::GetCameraCommon(const ComponentPtr_t & _pComponent) -> Render_t
1252{
1253 const auto DisableDepthRender = GetDepthRender(false, false, false);
1254
1255 using Size_t = ::std::tuple<GLint, GLint>;
1256 using fnBkSurfaceSize_t = ::std::function<Size_t(void)>;
1257
1258 const auto pCamera = _pComponent;
1259
1260 const fnBkSurfaceSize_t GetScaleBkSurfaceSize = [=](void)
1261 {
1262 const float Scale = (*pCamera)[uT("scale")];
1263
1264 const auto Width = static_cast<GLint>(Scale * m_Width);
1265 const auto Height = static_cast<GLint>(Scale * (m_Height - m_Top));
1266
1267 return Size_t{ Width, Height };
1268 };
1269
1270 const fnBkSurfaceSize_t GetWindowBkSurfaceSize = [=](void)
1271 {
1272 return Size_t{ m_Width, m_Height - m_Top };
1273 };
1274
1275 const fnBkSurfaceSize_t GetUserBkSurfaceSize = [=](void)
1276 {
1277 const int Width = (*pCamera)[uT("width")];
1278 const int Height = (*pCamera)[uT("height")];
1279
1280 return Size_t{ static_cast<GLint>(Width), static_cast<GLint>(Height) };
1281 };
1282
1283 const auto IsScaleBkSurfaceSize =
1284 (*pCamera)[uT("scale")].IsType<float>();
1285 const auto IsUserBkSurfaceSize =
1286 (*pCamera)[uT("width")].IsType<int>() &&
1287 (*pCamera)[uT("height")].IsType<int>();
1288
1289 const auto GetBkSurfaceSize =
1290 (IsScaleBkSurfaceSize) ? GetScaleBkSurfaceSize :
1291 (IsUserBkSurfaceSize) ? GetUserBkSurfaceSize :
1292 GetWindowBkSurfaceSize;
1293
1294 const auto [Width, Height] = GetBkSurfaceSize();
1295
1296 // Функция должна обязательно вызываться не только при рендеринге, но и при
1297 // создании камеры, чтобы внеэкранная поверхность создавалась с корректными
1298 // размерами.
1299 glViewport(0, 0, Width, Height); // (0, 0) - левый нижний угол!
1300
1301 return [=](void)
1302 {
1303 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1304
1305 DisableDepthRender();
1306
1307 glDisable(GL_BLEND);
1308 glDisable(GL_DITHER);
1309
1310 glEnable(GL_CULL_FACE);
1311 glCullFace(GL_BACK);
1312 glFrontFace(GL_CCW);
1313
1314 const auto [Width, Height] = GetBkSurfaceSize();
1315
1316 glViewport(0, 0, Width, Height); // (0, 0) - левый нижний угол!
1317 };
1318}
1319
1321 const ComponentPtr_t & _pComponent) -> Render_t
1322{
1323 const auto CommonRender = GetCameraCommon(_pComponent);
1324
1325 const auto ServiceComponents = CapturingServiceComponent::Get(_pComponent,
1326 {
1327 { uT("Position"), api::Component::Make({}) },
1328 });
1329
1330 return [=](void)
1331 {
1332 CommonRender();
1333
1334 GLfloat Viewport[4] = { 0 };
1335 glGetFloatv(GL_VIEWPORT, Viewport);
1336
1337 // 25 Август 2019 20:19 (unicornum.verum@gmail.com)
1338 TODO("Тест не проверяет возможность изменения смещения во время работы программы");
1339 const Component::Position Offset{ *ServiceComponents[0] };
1340
1341 auto & Matrix = m_pConstants->Get<::Camera>();
1342
1343 Matrix.Projection = ::glm::transpose(::glm::ortho(
1344 Viewport[0] + Offset.X,
1345 Viewport[0] + Viewport[2] + Offset.X,
1346 Viewport[1] + Viewport[3] + Offset.Y,
1347 Viewport[1] + Offset.Y,
1348 1.0f, -1.0f));
1349 Matrix.View = ::glm::transpose(::glm::identity<::glm::mat4>());
1350 Matrix.ViewInverse = ::glm::transpose(
1351 ::glm::inverse(::glm::identity<::glm::mat4>()));
1352
1353 (*_pComponent)[uT("view")] = Matrix.View;
1354 (*_pComponent)[uT("projection")] = Matrix.Projection;
1355 };
1356}
1357
1358auto OpenGLCommonShader::GetCameraPerspective(
1359 const ComponentPtr_t & _pComponent) -> Render_t
1360{
1361 const auto CommonRender = GetCameraCommon(_pComponent);
1362
1363 const auto ServiceComponents = CapturingServiceComponent::Get(_pComponent,
1364 {
1365 { uT("Position"), api::Component::Make({}) },
1366 { uT("Rotation"), api::Component::Make({}) },
1367 });
1368
1369 return [=](void)
1370 {
1371 CommonRender();
1372
1373 GLfloat Viewport[4] = { 0 };
1374 glGetFloatv(GL_VIEWPORT, Viewport);
1375
1376 auto & Matrix = m_pConstants->Get<::Camera>();
1377
1378 // ************************** Матрица проекции ************************** //
1379
1380 const auto AngleY = (float)(*_pComponent)[uT("fov")].Default(90.0f) *
1381 ::alicorn::extension::cpp::math::Constant<float>::DegreeToRadian;
1382 const float zNear = (*_pComponent)[uT("znear")].Default(0.01f);
1383 const float zFar = (*_pComponent)[uT("zfar")].Default(200.0f);
1384
1385 Matrix.Projection = ::glm::transpose(::glm::perspectiveFovRH(AngleY,
1386 Viewport[2], Viewport[3], zFar, zNear));
1387
1388 // **************************** Матрица вида **************************** //
1389
1390 // Точка, куда смотрит камера - задается как компонент Data.Position.
1391 const Component::Position Look{ *ServiceComponents[0] };
1392
1393 const auto GetEye = [&](void) -> ::glm::vec3
1394 {
1395 // Расстояние от камеры до Look.
1396 const float Distance = (*_pComponent)[uT("distance")].Default(0.0f);
1397
1398 // Точка, где расположена камера - вычисляется на основе Look, Distance и
1399 // компонента Data.Rotation.
1400
1401 const Component::Position Rot{ *ServiceComponents[1] };
1402
1403 ::glm::mat4 Transform = ::glm::identity<::glm::mat4>();
1404
1405 Transform = ::glm::translate(Transform,
1406 ::glm::vec3{ Look.X, Look.Y, Look.Z });
1407 Transform = ::glm::rotate(Transform,
1408 Rot.Z, ::glm::vec3{ 0.0f, 0.0f, 1.0f });
1409 Transform = ::glm::rotate(Transform,
1410 Rot.Y, ::glm::vec3{ 0.0f, 1.0f, 0.0f });
1411 Transform = ::glm::rotate(Transform,
1412 Rot.X, ::glm::vec3{ 1.0f, 0.0f, 0.0f });
1413
1414 return Transform * ::glm::vec4{ Distance + 0.1f, 0.0f, 0.0f, 1.0f };
1415 };
1416
1417 const auto View = ::glm::lookAtRH(
1418 GetEye(),
1419 ::glm::vec3{ Look.X, Look.Y, Look.Z },
1420 ::glm::vec3{ 0.0f, 0.0f, 1.0f }); // Up
1421
1422 Matrix.View = ::glm::transpose(View);
1423 Matrix.ViewInverse = ::glm::transpose(::glm::inverse(View));
1424
1425 (*_pComponent)[uT("view")] = Matrix.View;
1426 (*_pComponent)[uT("projection")] = Matrix.Projection;
1427 };
1428}
1429
1430} // namespace renderer
1431
1432} // namespace api
1433
1434} // namespace covellite
static ComponentPtr_t Make(const SourceParams_t &)
Функция создания объектов компонентов.
Определения Component.inl:29
Render_t GetCameraOrthographic(const ComponentPtr_t &)
Определения OpenGLCommonShader.cpp:1320
Render_t CreateTransform(const ComponentPtr_t &) override
Определения OpenGLCommonShader.cpp:1074
Класс входит в проект Covellite.Api Класс формата вертексного буфера.
Определения Vertex.hpp:34