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