OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Shader Class Reference

#include <C4Shader.h>

Public Member Functions

 C4Shader ()
 
 ~C4Shader ()
 
bool Initialised () const
 
GLint GetUniform (int iUniform) const
 
bool HaveUniform (int iUniform) const
 
GLint GetAttribute (int iAttribute) const
 
void AddDefine (const char *name)
 
void AddVertexSlice (int iPos, const char *szText)
 
void AddFragmentSlice (int iPos, const char *szText)
 
void AddVertexSlices (const char *szWhat, const char *szText, const char *szSource="", int iFileTime=0)
 
void AddFragmentSlices (const char *szWhat, const char *szText, const char *szSource="", int iFileTime=0)
 
bool LoadFragmentSlices (C4GroupSet *pGroupSet, const char *szFile)
 
bool LoadVertexSlices (C4GroupSet *pGroupSet, const char *szFile)
 
void SetScriptCategories (const std::vector< std::string > &categories)
 
bool Init (const char *szWhat, const char **szUniforms, const char **szAttributes)
 
bool Refresh ()
 
void ClearSlices ()
 
void Clear ()
 

Static Public Member Functions

static bool IsLogging ()
 

Friends

class C4ShaderCall
 
class C4ScriptUniform
 

Detailed Description

Definition at line 61 of file C4Shader.h.

Constructor & Destructor Documentation

C4Shader::C4Shader ( )

Definition at line 45 of file C4Shader.cpp.

46  : LastRefresh()
47 {
48 
49 }
C4Shader::~C4Shader ( )

Definition at line 51 of file C4Shader.cpp.

References Clear().

52 {
53  Clear();
54 }
void Clear()
Definition: C4Shader.cpp:333

Here is the call graph for this function:

Member Function Documentation

void C4Shader::AddDefine ( const char *  name)

Definition at line 63 of file C4Shader.cpp.

References AddFragmentSlice(), AddVertexSlice(), FormatString(), and StdStrBuf::getData().

Referenced by C4DefAdditionalResourcesLoader::AddShaderSlices(), and CStdGL::PrepareSpriteShader().

64 {
65  StdStrBuf define = FormatString("#define %s", name);
66  AddVertexSlice(-1, define.getData());
67  AddFragmentSlice(-1, define.getData());
68 }
const char * getData() const
Definition: StdBuf.h:442
void AddFragmentSlice(int iPos, const char *szText)
Definition: C4Shader.cpp:75
void AddVertexSlice(int iPos, const char *szText)
Definition: C4Shader.cpp:70
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270

Here is the call graph for this function:

Here is the caller graph for this function:

void C4Shader::AddFragmentSlice ( int  iPos,
const char *  szText 
)

Definition at line 75 of file C4Shader.cpp.

Referenced by AddDefine().

76 {
77  AddSlice(FragmentSlices, iPos, szText, nullptr, 0, 0);
78 }

Here is the caller graph for this function:

void C4Shader::AddFragmentSlices ( const char *  szWhat,
const char *  szText,
const char *  szSource = "",
int  iFileTime = 0 
)

Definition at line 85 of file C4Shader.cpp.

Referenced by C4FoW::GetFramebufShader(), C4FoW::GetRenderShader(), and Refresh().

86 {
87  AddSlices(FragmentSlices, szWhat, szText, szSource, iSourceTime);
88 }

Here is the caller graph for this function:

void C4Shader::AddVertexSlice ( int  iPos,
const char *  szText 
)

Definition at line 70 of file C4Shader.cpp.

Referenced by AddDefine().

71 {
72  AddSlice(VertexSlices, iPos, szText, nullptr, 0, 0);
73 }

Here is the caller graph for this function:

void C4Shader::AddVertexSlices ( const char *  szWhat,
const char *  szText,
const char *  szSource = "",
int  iFileTime = 0 
)

Definition at line 80 of file C4Shader.cpp.

Referenced by C4FoW::GetFramebufShader(), and C4FoW::GetRenderShader().

81 {
82  AddSlices(VertexSlices, szWhat, szText, szSource, iSourceTime);
83 }

Here is the caller graph for this function:

void C4Shader::Clear ( )

Definition at line 333 of file C4Shader.cpp.

Referenced by C4Sky::Clear(), CStdGL::Clear(), CStdGL::PrepareSpriteShader(), and ~C4Shader().

334 {
335 #ifndef USE_CONSOLE
336  if (!hProg) return;
337  // Need to be detached, then deleted
338  glDeleteProgram(hProg);
339  hProg = 0;
340  // Clear uniform data
341  Uniforms.clear();
342  Attributes.clear();
343 #endif
344 }

Here is the caller graph for this function:

void C4Shader::ClearSlices ( )

Definition at line 322 of file C4Shader.cpp.

Referenced by C4FoW::GetFramebufShader(), C4FoW::GetRenderShader(), and CStdGL::PrepareSpriteShader().

323 {
324  VertexSlices.clear();
325  FragmentSlices.clear();
326  iTexCoords = 0;
327  // Script slices
328  ScriptSlicesLoaded = false;
329  Categories.clear();
330  ScriptShaders.clear();
331 }

Here is the caller graph for this function:

GLint C4Shader::GetAttribute ( int  iAttribute) const
inline

Definition at line 127 of file C4Shader.h.

Referenced by C4LandscapeRenderGL::Draw(), C4ShaderCall::GetAttribute(), and C4FoWRegion::Render().

128  {
129  return iAttribute >= 0 && static_cast<unsigned int>(iAttribute) < Attributes.size() ? Attributes[iAttribute].address : -1;
130  }

Here is the caller graph for this function:

bool C4Shader::HaveUniform ( int  iUniform) const
inline

Definition at line 122 of file C4Shader.h.

References GetUniform().

Referenced by C4ShaderCall::AllocTexUnit(), C4LandscapeRenderGL::Draw(), C4ShaderCall::SetUniform1f(), C4ShaderCall::SetUniform1fv(), C4ShaderCall::SetUniform1i(), C4ShaderCall::SetUniform1iv(), C4ShaderCall::SetUniform1ui(), C4ShaderCall::SetUniform1uiv(), C4ShaderCall::SetUniform2f(), C4ShaderCall::SetUniform2fv(), C4ShaderCall::SetUniform2i(), C4ShaderCall::SetUniform2iv(), C4ShaderCall::Setuniform2ui(), C4ShaderCall::SetUniform2uiv(), C4ShaderCall::SetUniform3f(), C4ShaderCall::SetUniform3fv(), C4ShaderCall::SetUniform3i(), C4ShaderCall::SetUniform3iv(), C4ShaderCall::Setuniform3ui(), C4ShaderCall::SetUniform3uiv(), C4ShaderCall::SetUniform4f(), C4ShaderCall::SetUniform4fv(), C4ShaderCall::SetUniform4i(), C4ShaderCall::SetUniform4iv(), C4ShaderCall::Setuniform4ui(), C4ShaderCall::SetUniform4uiv(), C4ShaderCall::SetUniformMatrix2x3fv(), C4ShaderCall::SetUniformMatrix3x3(), C4ShaderCall::SetUniformMatrix3x3fv(), C4ShaderCall::SetUniformMatrix3x3Transpose(), C4ShaderCall::SetUniformMatrix3x4(), C4ShaderCall::SetUniformMatrix3x4fv(), C4ShaderCall::SetUniformMatrix4x4(), and C4ShaderCall::SetUniformMatrix4x4fv().

123  {
124  return GetUniform(iUniform) != GLint(-1);
125  }
GLint GetUniform(int iUniform) const
Definition: C4Shader.h:117

Here is the call graph for this function:

Here is the caller graph for this function:

bool C4Shader::Init ( const char *  szWhat,
const char **  szUniforms,
const char **  szAttributes 
)

Definition at line 346 of file C4Shader.cpp.

References StdStrBuf::Copy(), FormatString(), StdStrBuf::getData(), IsLogging(), C4TimeMilliseconds::Now(), CStdGL::ObjectLabel(), pGL, ShaderLog(), and ShaderLogF().

Referenced by C4FoW::GetFramebufShader(), C4FoW::GetRenderShader(), CStdGL::PrepareSpriteShader(), and Refresh().

347 {
348  Name.Copy(szWhat);
349  LastRefresh = C4TimeMilliseconds::Now();
350 
351  if (!ScriptSlicesLoaded)
352  {
353  Categories.emplace_back(szWhat);
354  LoadScriptSlices();
355  }
356 
357  StdStrBuf VertexShader = Build(VertexSlices, true),
358  FragmentShader = Build(FragmentSlices, true);
359 
360  // Dump
361  if (C4Shader::IsLogging())
362  {
363  ShaderLogF("******** Vertex shader for %s:", szWhat);
364  ShaderLog(VertexShader.getData());
365  ShaderLogF("******** Fragment shader for %s:", szWhat);
366  ShaderLog(FragmentShader.getData());
367  }
368 
369 #ifndef USE_CONSOLE
370  // Attempt to create shaders
371  const GLuint hVert = Create(GL_VERTEX_SHADER,
372  FormatString("%s vertex shader", szWhat).getData(),
373  VertexShader.getData());
374  const GLuint hFrag = Create(GL_FRAGMENT_SHADER,
375  FormatString("%s fragment shader", szWhat).getData(),
376  FragmentShader.getData());
377 
378  if(!hFrag || !hVert)
379  {
380  if (hFrag) glDeleteShader(hFrag);
381  if (hVert) glDeleteShader(hVert);
382  return false;
383  }
384 
385  // Link program
386  const GLuint hNewProg = glCreateProgram();
387  pGL->ObjectLabel(GL_PROGRAM, hNewProg, -1, szWhat);
388  glAttachShader(hNewProg, hVert);
389  glAttachShader(hNewProg, hFrag);
390  glLinkProgram(hNewProg);
391  // Delete vertex and fragment shader after we linked the program
392  glDeleteShader(hFrag);
393  glDeleteShader(hVert);
394 
395  // Link successful?
396  DumpInfoLog(FormatString("%s shader program", szWhat).getData(), hNewProg, true);
397  GLint status;
398  glGetProgramiv(hNewProg, GL_LINK_STATUS, &status);
399  if(status != GL_TRUE) {
400  glDeleteProgram(hNewProg);
401  ShaderLogF(" gl: Failed to link %s shader!", szWhat);
402  return false;
403  }
404  ShaderLogF(" gl: %s shader linked successfully", szWhat);
405 
406  // Everything successful, delete old shader
407  if (hProg != 0) glDeleteProgram(hProg);
408  hProg = hNewProg;
409 
410  // Allocate uniform and attribute arrays
411  int iUniformCount = 0;
412  if (szUniforms != nullptr)
413  while (szUniforms[iUniformCount])
414  iUniformCount++;
415  Uniforms.resize(iUniformCount);
416 
417  int iAttributeCount = 0;
418  if (szAttributes != nullptr)
419  while (szAttributes[iAttributeCount])
420  iAttributeCount++;
421  Attributes.resize(iAttributeCount);
422 
423  // Get uniform and attribute locations. Note this is expected to fail for a few of them
424  // because the respective uniforms got optimized out!
425  for (int i = 0; i < iUniformCount; i++) {
426  Uniforms[i].address = glGetUniformLocation(hProg, szUniforms[i]);
427  Uniforms[i].name = szUniforms[i];
428  ShaderLogF("Uniform %s = %d", szUniforms[i], Uniforms[i].address);
429  }
430 
431  for (int i = 0; i < iAttributeCount; i++) {
432  Attributes[i].address = glGetAttribLocation(hProg, szAttributes[i]);
433  Attributes[i].name = szAttributes[i];
434  ShaderLogF("Attribute %s = %d", szAttributes[i], Attributes[i].address);
435  }
436 
437 #endif
438 
439  return true;
440 }
const char * getData() const
Definition: StdBuf.h:442
bool ShaderLog(const char *szMessage)
Definition: C4Log.cpp:341
static bool IsLogging()
Definition: C4Shader.cpp:663
bool ShaderLogF(const char *strMessage...)
Definition: C4Log.cpp:354
void ObjectLabel(uint32_t identifier, uint32_t name, int32_t length, const char *label)
Definition: C4DrawGL.cpp:274
CStdGL * pGL
Definition: C4DrawGL.cpp:905
void Copy()
Definition: StdBuf.h:467
static C4TimeMilliseconds Now()
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270

Here is the call graph for this function:

Here is the caller graph for this function:

bool C4Shader::Initialised ( ) const
inline

Definition at line 106 of file C4Shader.h.

Referenced by C4LandscapeRenderGL::Draw(), C4FoW::GetFramebufShader(), C4FoW::GetRenderShader(), and StdMeshMaterialProgram::IsCompiled().

107  {
108 #ifndef USE_CONSOLE
109  return hProg != 0;
110 #else
111  return true;
112 #endif
113  }

Here is the caller graph for this function:

bool C4Shader::IsLogging ( )
static

Definition at line 663 of file C4Shader.cpp.

References Application, Config, C4ConfigGraphics::DebugOpenGL, C4Config::Graphics, and C4Application::isEditor.

Referenced by Init(), and OpenExtraLogs().

663 { return Config.Graphics.DebugOpenGL != 0 || !!Application.isEditor; }
int32_t DebugOpenGL
Definition: C4Config.h:117
C4Config Config
Definition: C4Config.cpp:833
C4ConfigGraphics Graphics
Definition: C4Config.h:253
C4Application Application
Definition: C4Globals.cpp:44

Here is the caller graph for this function:

bool C4Shader::LoadFragmentSlices ( C4GroupSet pGroupSet,
const char *  szFile 
)

Definition at line 90 of file C4Shader.cpp.

Referenced by C4DefAdditionalResourcesLoader::AddShaderSlices(), and CStdGL::PrepareSpriteShader().

91 {
92  return LoadSlices(FragmentSlices, pGroups, szFile);
93 }

Here is the caller graph for this function:

bool C4Shader::LoadVertexSlices ( C4GroupSet pGroupSet,
const char *  szFile 
)

Definition at line 95 of file C4Shader.cpp.

Referenced by CStdGL::PrepareSpriteShader().

96 {
97  return LoadSlices(VertexSlices, pGroups, szFile);
98 }

Here is the caller graph for this function:

bool C4Shader::Refresh ( )

Definition at line 443 of file C4Shader.cpp.

References _MAX_PATH, AddFragmentSlices(), C4Config::AtRelativePath(), C4Group::Close(), Config, FileExists(), FileTime(), FormatString(), StdStrBuf::getData(), GetFilename(), GetParentPath(), C4ScriptShader::GetShaderIDs(), Init(), C4Group::LoadEntryString(), C4TimeMilliseconds::Now(), C4Group::Open(), ScriptShader, SEqual(), and ShaderLogF().

444 {
445  // Update last refresh. Keep a local copy around though to identify added script shaders.
446  LastRefresh = C4TimeMilliseconds::Now();
447 
448  auto next = ScriptShader.GetShaderIDs(Categories);
449  std::set<int> toAdd, toRemove;
450  std::set_difference(ScriptShaders.begin(), ScriptShaders.end(), next.begin(), next.end(), std::inserter(toRemove, toRemove.end()));
451  std::set_difference(next.begin(), next.end(), ScriptShaders.begin(), ScriptShaders.end(), std::inserter(toAdd, toAdd.end()));
452  ScriptShaders = next;
453 
454  auto removeSlices = [&](ShaderSliceList::iterator& pSlice)
455  {
456  StdCopyStrBuf Source = pSlice->Source;
457 
458  // Okay, remove all slices that came from this file
459  ShaderSliceList::iterator pNext;
460  for (; pSlice != FragmentSlices.end(); pSlice = pNext)
461  {
462  pNext = pSlice; pNext++;
463  if (SEqual(pSlice->Source.getData(), Source.getData()))
464  FragmentSlices.erase(pSlice);
465  }
466  };
467 
468  // Find slices where the source file has updated.
469  std::vector<StdCopyStrBuf> sourcesToUpdate;
470  for (ShaderSliceList::iterator pSlice = FragmentSlices.begin(); pSlice != FragmentSlices.end(); pSlice++)
471  if (pSlice->Source.getLength())
472  {
473  if (pSlice->Source.BeginsWith("[script "))
474  {
475  // TODO: Maybe save id instead of parsing the string here.
476  int sid = -1;
477  sscanf(pSlice->Source.getData(), "[script %d", &sid);
478  if (toRemove.find(sid) != toRemove.end())
479  removeSlices(pSlice);
480  // Note: script slices don't change, so we don't have to handle updates like for files.
481  }
482  else if (FileExists(pSlice->Source.getData()) &&
483  FileTime(pSlice->Source.getData()) > pSlice->SourceTime)
484  {
485  sourcesToUpdate.push_back(pSlice->Source);
486  removeSlices(pSlice);
487  }
488  }
489 
490  // Anything to do?
491  if (toAdd.size() == 0 && toRemove.size() == 0 && sourcesToUpdate.size() == 0)
492  return true;
493 
494  // Process file reloading.
495  for (auto& Source : sourcesToUpdate)
496  {
497  char szParentPath[_MAX_PATH+1]; C4Group Group;
498  StdStrBuf Shader;
499  GetParentPath(Source.getData(),szParentPath);
500  if(!Group.Open(szParentPath) ||
501  !Group.LoadEntryString(GetFilename(Source.getData()),&Shader) ||
502  !Group.Close())
503  {
504  ShaderLogF(" gl: Failed to refresh %s shader from %s!", Name.getData(), Source.getData());
505  return false;
506  }
507 
508  // Load slices
509  int iSourceTime = FileTime(Source.getData());
510  StdStrBuf WhatSrc = FormatString("file %s", Config.AtRelativePath(Source.getData()));
511  AddFragmentSlices(WhatSrc.getData(), Shader.getData(), Source.getData(), iSourceTime);
512  }
513 
514  // Process new script slices.
515  for (int id : toAdd)
516  {
517  LoadScriptSlice(id);
518  }
519 
520 #ifndef USE_CONSOLE
521  std::vector<const char*> UniformNames(Uniforms.size() + 1);
522  for (std::size_t i = 0; i < Uniforms.size(); ++i)
523  UniformNames[i] = Uniforms[i].name;
524  UniformNames[Uniforms.size()] = nullptr;
525 
526  std::vector<const char*> AttributeNames(Attributes.size() + 1);
527  for (std::size_t i = 0; i < Attributes.size(); ++i)
528  AttributeNames[i] = Attributes[i].name;
529  AttributeNames[Attributes.size()] = nullptr;
530 #endif
531 
532  // Reinitialise
533  StdCopyStrBuf What(Name);
534  if (!Init(What.getData(),
535 #ifndef USE_CONSOLE
536  &UniformNames[0],
537  &AttributeNames[0]
538 #else
539  nullptr,
540  nullptr
541 #endif
542  ))
543  return false;
544 
545  return true;
546 }
char * GetFilename(char *szPath)
Definition: StdFile.cpp:45
const char * getData() const
Definition: StdBuf.h:442
void AddFragmentSlices(const char *szWhat, const char *szText, const char *szSource="", int iFileTime=0)
Definition: C4Shader.cpp:85
C4Config Config
Definition: C4Config.cpp:833
#define _MAX_PATH
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
bool GetParentPath(const char *szFilename, char *szBuffer)
Definition: StdFile.cpp:189
int FileTime(const char *fname)
bool Open(const char *szGroupName, bool fCreate=false)
Definition: C4Group.cpp:514
bool Close()
Definition: C4Group.cpp:755
bool FileExists(const char *szFileName)
bool LoadEntryString(const char *szEntryName, StdStrBuf *Buf)
Definition: C4Group.cpp:1932
bool Init(const char *szWhat, const char **szUniforms, const char **szAttributes)
Definition: C4Shader.cpp:346
C4ScriptShader ScriptShader
Definition: C4Shader.cpp:717
bool ShaderLogF(const char *strMessage...)
Definition: C4Log.cpp:354
std::set< int > GetShaderIDs(const std::vector< std::string > &cats)
Definition: C4Shader.cpp:719
const char * AtRelativePath(const char *szFilename)
Definition: C4Config.cpp:656
static C4TimeMilliseconds Now()
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270

Here is the call graph for this function:

void C4Shader::SetScriptCategories ( const std::vector< std::string > &  categories)

Definition at line 100 of file C4Shader.cpp.

Referenced by C4DefAdditionalResourcesLoader::AddShaderSlices(), and CStdGL::PrepareSpriteShader().

101 {
102  assert(!ScriptSlicesLoaded && "Can't change shader categories after initialization");
103  Categories = categories;
104 }

Here is the caller graph for this function:

Friends And Related Function Documentation

friend class C4ScriptUniform
friend

Definition at line 64 of file C4Shader.h.

friend class C4ShaderCall
friend

Definition at line 63 of file C4Shader.h.


The documentation for this class was generated from the following files: