34 const char *MsgSourceToStr(GLenum source)
38 case GL_DEBUG_SOURCE_API_ARB:
return "API";
39 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
return "window system";
40 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
return "shader compiler";
41 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
return "third party";
42 case GL_DEBUG_SOURCE_APPLICATION_ARB:
return "application";
43 case GL_DEBUG_SOURCE_OTHER_ARB:
return "other";
44 default:
return "<unknown>";
48 const char *MsgTypeToStr(GLenum
type)
52 case GL_DEBUG_TYPE_ERROR_ARB:
return "error";
53 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
return "deprecation warning";
54 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
return "undefined behavior warning";
55 case GL_DEBUG_TYPE_PORTABILITY_ARB:
return "portability warning";
56 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
return "performance warning";
57 case GL_DEBUG_TYPE_OTHER_ARB:
return "other message";
58 default:
return "unknown message";
62 const char *MsgSeverityToStr(GLenum severity)
66 case GL_DEBUG_SEVERITY_HIGH_ARB:
return "high";
67 case GL_DEBUG_SEVERITY_MEDIUM_ARB:
return "medium";
68 case GL_DEBUG_SEVERITY_LOW_ARB:
return "low";
69 #ifdef GL_DEBUG_SEVERITY_NOTIFICATION
70 case GL_DEBUG_SEVERITY_NOTIFICATION:
return "notification";
72 default:
return "<unknown>";
76 void GLAPIENTRY OpenGLDebugProc(GLenum source, GLenum
type, GLuint
id, GLenum severity, GLsizei length,
const char* message,
const void* userParam)
78 const char *msg_source = MsgSourceToStr(source);
79 const char *msg_type = MsgTypeToStr(
type);
80 const char *msg_severity = MsgSeverityToStr(severity);
82 LogSilentF(
" gl: %s severity %s %s: %s", msg_severity, msg_source, msg_type, message);
83 #ifdef USE_WIN32_WINDOWS
84 if (IsDebuggerPresent() && severity == GL_DEBUG_SEVERITY_HIGH_ARB)
91 NextVAOID(VAOIDs.end())
140 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
149 if (clipRect.
Wdt<=0 || clipRect.
Hgt<=0)
169 if (!sfcToSurface)
return false;
171 if (sfcToSurface->
Locked)
return false;
179 if (!sfcToSurface->
pCtx->
Select())
return false;
236 if (ssc & C4SSC_MOD2) shader.
AddDefine(
"OC_CLRMOD_MOD2");
237 if (ssc & C4SSC_NORMAL) shader.
AddDefine(
"OC_WITH_NORMALMAP");
238 if (ssc & C4SSC_LIGHT) shader.
AddDefine(
"OC_DYNAMIC_LIGHT");
239 if (ssc & C4SSC_BASE) shader.
AddDefine(
"OC_HAVE_BASE");
240 if (ssc & C4SSC_OVERLAY) shader.
AddDefine(
"OC_HAVE_OVERLAY");
242 if (additionalDefines)
243 for (
const char*
const* define = additionalDefines; *define !=
nullptr; ++define)
254 if (additionalSlices)
255 for (
const char*
const* slice = additionalSlices; *slice !=
nullptr; ++slice)
258 if (!shader.
Init(name, uniformNames, attributeNames))
270 glObjectLabel(identifier, name, length, label);
276 if (!pWindow)
return nullptr;
280 #ifdef WITH_QT_EDITOR
283 pCtx =
new CStdGLCtxQt();
295 Log(
" gl: failed to create context.");
299 has_khr_debug = epoxy_has_gl_extension(
"GL_KHR_debug") || epoxy_gl_version() >= 43;
302 if (first_ctx)
Log(
" gl: Setting OpenGLDebugProc callback");
303 glDebugMessageCallback(&OpenGLDebugProc,
nullptr);
304 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
306 glEnable(GL_DEBUG_OUTPUT);
312 const auto *gl_vendor =
reinterpret_cast<const char *
>(glGetString(GL_VENDOR));
313 const auto *gl_renderer =
reinterpret_cast<const char *
>(glGetString(GL_RENDERER));
314 const auto *gl_version =
reinterpret_cast<const char *
>(glGetString(GL_VERSION));
315 LogF(
"GL %s on %s (%s)", gl_version ? gl_version :
"", gl_renderer ? gl_renderer :
"", gl_vendor ? gl_vendor :
"");
320 if (epoxy_is_desktop_gl() && epoxy_gl_version() >= 30)
322 GLint gl_extension_count = 0;
323 glGetIntegerv(GL_NUM_EXTENSIONS, &gl_extension_count);
324 if (gl_extension_count == 0)
330 LogSilentF(
"%d available extensions:", gl_extension_count);
331 for (GLint i = 0; i < gl_extension_count; ++i)
333 const char *gl_extension = (
const char*)glGetStringi(GL_EXTENSIONS, i);
340 const char *gl_extensions =
reinterpret_cast<const char *
>(glGetString(GL_EXTENSIONS));
341 LogSilentF(
"GLExt: %s", gl_extensions ? gl_extensions :
"");
347 #ifdef WITH_QT_EDITOR
360 glBlendFunc(GL_SRC_ALPHA, iAdditive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA);
366 const float fMod[4] = {
367 ((dwModClr >> 16) & 0xff) / 255.0f,
368 ((dwModClr >> 8) & 0xff) / 255.0f,
369 ((dwModClr ) & 0xff) / 255.0f,
370 ((dwModClr >> 24) & 0xff) / 255.0f
379 glBindTexture(GL_TEXTURE_2D, baseTex);
385 glBindTexture(GL_TEXTURE_2D, overlayTex);
387 const float fOverlayModClr[4] = {
388 ((dwOverlayModClr >> 16) & 0xff) / 255.0f,
389 ((dwOverlayModClr >> 8) & 0xff) / 255.0f,
390 ((dwOverlayModClr ) & 0xff) / 255.0f,
391 ((dwOverlayModClr >> 24) & 0xff) / 255.0f
397 if(
pFoW !=
nullptr && normalTex != 0)
400 glBindTexture(GL_TEXTURE_2D, normalTex);
413 float lightTransform[6];
422 float ambientTransform[6];
450 if (
pFoW !=
nullptr && normalTex != 0)
455 const float sx = sqrt(pTransform->
mat[0]*pTransform->
mat[0] + pTransform->
mat[1]*pTransform->
mat[1]);
456 const float sy = sqrt(pTransform->
mat[3]*pTransform->
mat[3] + pTransform->
mat[4]*pTransform->
mat[4]);
462 transform(0, 0) = pTransform->
mat[0];
463 transform(0, 1) = pTransform->
mat[1];
464 transform(0, 2) = 0.0f;
465 transform(0, 3) = pTransform->
mat[2];
466 transform(1, 0) = pTransform->
mat[3];
467 transform(1, 1) = pTransform->
mat[4];
468 transform(1, 2) = 0.0f;
469 transform(1, 3) = pTransform->
mat[5];
470 transform(2, 0) = 0.0f;
471 transform(2, 1) = 0.0f;
472 transform(2, 2) = sz;
473 transform(2, 3) = 0.0f;
474 transform(3, 0) = pTransform->
mat[6];
475 transform(3, 1) = pTransform->
mat[7];
476 transform(3, 2) = 0.0f;
477 transform(3, 3) = pTransform->
mat[8];
478 modelview *= transform;
484 if (
pFoW !=
nullptr && normalTex != 0)
499 const unsigned int BATCH_SIZE = 256;
506 for(
unsigned int i = 0; i < n_vertices; i += BATCH_SIZE)
511 SetupMultiBlt(*shader_call,
nullptr, 0, 0, 0, 0, &transform);
512 for(
unsigned int i = 0; i < n_vertices; i += BATCH_SIZE)
524 for(
unsigned int i = 0; i < n_vertices; i += 2)
526 const float x1 = vertices[i].
ftx;
527 const float y1 = vertices[i].
fty;
528 const float x2 = vertices[i+1].
ftx;
529 const float y2 = vertices[i+1].
fty;
531 float offx = y1 - y2;
532 float offy = x2 - x1;
533 float l = sqrtf(offx * offx + offy * offy);
539 tri_vertices[3*i + 0].
ftx = x1 + offx; tri_vertices[3*i + 0].
fty = y1 + offy;
540 tri_vertices[3*i + 1].
ftx = x1 - offx; tri_vertices[3*i + 1].
fty = y1 - offy;
541 tri_vertices[3*i + 2].
ftx = x2 - offx; tri_vertices[3*i + 2].
fty = y2 - offy;
542 tri_vertices[3*i + 3].
ftx = x2 + offx; tri_vertices[3*i + 3].
fty = y2 + offy;
544 for(
int j = 0; j < 4; ++j)
546 tri_vertices[3*i + 0].
color[j] = vertices[i].
color[j];
547 tri_vertices[3*i + 1].
color[j] = vertices[i].
color[j];
548 tri_vertices[3*i + 2].
color[j] = vertices[i + 1].
color[j];
549 tri_vertices[3*i + 3].
color[j] = vertices[i + 1].
color[j];
552 tri_vertices[3*i + 0].
tx = 0.f; tri_vertices[3*i + 0].
ty = 0.f;
553 tri_vertices[3*i + 1].
tx = 0.f; tri_vertices[3*i + 1].
ty = 2.f;
554 tri_vertices[3*i + 2].
tx = 1.f; tri_vertices[3*i + 2].
ty = 2.f;
555 tri_vertices[3*i + 3].
tx = 1.f; tri_vertices[3*i + 3].
ty = 0.f;
557 tri_vertices[3*i + 4] = tri_vertices[3*i + 2];
558 tri_vertices[3*i + 5] = tri_vertices[3*i + 0];
574 delete[] tri_vertices;
608 glBindBuffer(GL_ARRAY_BUFFER,
GenericVBOs[vbo_index]);
612 glBufferData(GL_ARRAY_BUFFER, n_vertices *
sizeof(
C4BltVertex), vertices, GL_STREAM_DRAW);
616 glBufferSubData(GL_ARRAY_BUFFER, 0, n_vertices *
sizeof(
C4BltVertex), vertices);
622 const unsigned int vao_index = vbo_index + (has_tex ?
N_GENERIC_VBOS : 0);
623 const unsigned int vao_id =
GenericVAOs[vao_index];
624 const bool has_vao =
GetVAO(vao_id, vao);
625 glBindVertexArray(vao);
633 glEnableVertexAttribArray(position);
634 glEnableVertexAttribArray(color);
636 glEnableVertexAttribArray(texcoord);
639 glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE,
sizeof(
C4BltVertex),
reinterpret_cast<const uint8_t*
>(offsetof(
C4BltVertex, ftx)));
640 glVertexAttribPointer(color, 4, GL_UNSIGNED_BYTE, GL_TRUE,
sizeof(
C4BltVertex),
reinterpret_cast<const uint8_t*
>(offsetof(
C4BltVertex, color)));
642 glVertexAttribPointer(texcoord, 2, GL_FLOAT, GL_FALSE,
sizeof(
C4BltVertex),
reinterpret_cast<const uint8_t*
>(offsetof(
C4BltVertex, tx)));
648 glDrawArrays(GL_POINTS, 0, n_vertices);
651 glDrawArrays(GL_TRIANGLES, 0, n_vertices);
658 glBindVertexArray(0);
659 glBindBuffer(GL_ARRAY_BUFFER, 0);
666 if(haveBase) ssc |= C4SSC_BASE;
667 if(haveBase && haveOverlay) ssc |= C4SSC_OVERLAY;
668 if(
pFoW !=
nullptr) ssc |= C4SSC_LIGHT;
669 if(
pFoW !=
nullptr && haveBase && haveNormal) ssc |= C4SSC_NORMAL;
696 if(ssc & C4SSC_LIGHT) index += 6;
701 if(ssc & C4SSC_OVERLAY)
703 if( (ssc & C4SSC_NORMAL) && (ssc & C4SSC_LIGHT))
711 return shaders[index];
773 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
776 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
777 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
778 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
779 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
780 static const char * linedata =
"\xff\xff\xff\x00\xff\xff\xff\xff";
781 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, linedata);
785 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &
s);
799 glBindBuffer(GL_ARRAY_BUFFER, 0);
857 #ifdef USE_WIN32_WINDOWS
858 DWORD err = GetLastError();
861 #ifdef USE_WIN32_WINDOWS
864 FORMAT_MESSAGE_ALLOCATE_BUFFER |
865 FORMAT_MESSAGE_FROM_SYSTEM |
866 FORMAT_MESSAGE_IGNORE_INSERTS,
869 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
872 LogF(
" gl: GetLastError() = %d - %s", err,
StdStrBuf(lpMsgBuf).getData());
875 LogF(
" gl: %s", glGetString(GL_VENDOR));
876 LogF(
" gl: %s", glGetString(GL_RENDERER));
877 LogF(
" gl: %s", glGetString(GL_VERSION));
878 LogF(
" gl: %s", glGetString(GL_EXTENSIONS));
886 case GL_NO_ERROR:
return "No error";
887 case GL_INVALID_ENUM:
return "An unacceptable value is specified for an enumerated argument";
888 case GL_INVALID_VALUE:
return "A numeric argument is out of range";
889 case GL_INVALID_OPERATION:
return "The specified operation is not allowed in the current state";
890 case GL_INVALID_FRAMEBUFFER_OPERATION:
return "The framebuffer object is not complete";
891 case GL_OUT_OF_MEMORY:
return "There is not enough memory left to execute the command";
892 case GL_STACK_UNDERFLOW:
return "An attempt has been made to perform an operation that would cause an internal stack to underflow";
893 case GL_STACK_OVERFLOW:
return "An attempt has been made to perform an operation that would cause an internal stack to overflow";
894 default: assert(
false);
return "";
900 GLenum err = glGetError();
901 if (!err)
return true;
940 std::set<unsigned int>::iterator iter =
NextVAOID;
948 std::set<unsigned int>::iterator inserted_iter =
VAOIDs.insert(
NextVAOID,
id);
950 std::pair<std::set<unsigned int>::iterator,
bool> inserted =
VAOIDs.insert(
id);
951 assert(inserted.second ==
true);
952 std::set<unsigned int>::iterator inserted_iter = inserted.first;
958 unsigned int prev_id = id;
971 std::set<unsigned int>::iterator iter =
VAOIDs.find(vaoid);
972 assert(iter !=
VAOIDs.end());
977 if (vaoid < pCurrCtx->hVAOs.size() &&
pCurrCtx->
hVAOs[vaoid] != 0)
989 if (ctx !=
pCurrCtx && vaoid < ctx->hVAOs.size() && ctx->
hVAOs[vaoid] != 0)
990 if (std::find(ctx->VAOsToBeDeleted.begin(), ctx->VAOsToBeDeleted.end(), vaoid) == ctx->VAOsToBeDeleted.end())
991 ctx->VAOsToBeDeleted.push_back(vaoid);
999 unsigned int nextVaoID = 1;
1002 std::set<unsigned int>::iterator next_vao_iter =
NextVAOID;
1004 nextVaoID = *next_vao_iter + 1;
1007 assert(vaoid != nextVaoID);
1009 if (vaoid < nextVaoID || iter ==
NextVAOID)
1025 std::set<unsigned int>::iterator iter =
VAOIDs.end();
@ C4SSU_AmbientBrightness
@ C4SSU_MaterialShininess
bool Log(const char *szMessage)
bool LogSilentF(const char *strMessage,...)
bool LogF(const char *strMessage,...)
#define C4GFXBLIT_ADDITIVE
#define GetGreenValue(rgb)
#define GetBlueValue(rgb)
void Scale(MatrixType &mat, float sx, float sy, float sz)
void Translate(MatrixType &mat, float dx, float dy, float dz)
C4ConfigGraphics Graphics
virtual bool Error(const char *szMsg)
C4Rect GetClipRect() const
C4Rect GetOutRect() const
bool CreatePrimaryClipper(unsigned int iXRes, unsigned int iYRes)
C4ScriptUniform scriptUniform
void GetFragTransform(const struct FLOAT_RECT &vpRect, const C4Rect &clipRect, const C4Rect &outRect, float ambientTransform[6]) const
double GetBrightness() const
GLuint getSurfaceName() const
const C4FoW * getFoW() const
const FLOAT_RECT & getViewportRegion() const
void GetFragTransform(const C4Rect &clipRect, const C4Rect &outRect, float lightTransform[6]) const
void SetUniform1f(int iUniform, float gX) const
void SetUniformMatrix4x4(int iUniform, const StdMeshMatrix &matrix)
GLint AllocTexUnit(int iUniform)
GLint GetAttribute(int iAttribute) const
void SetUniform2f(int iUniform, float gX, float gY) const
void SetUniform4fv(int iUniform, int iLength, const float *pVals) const
void SetUniform3fv(int iUniform, int iLength, const float *pVals) const
void SetUniformMatrix2x3fv(int iUniform, int iLength, const float *pVals) const
void SetUniformMatrix3x3Transpose(int iUniform, const StdMeshMatrix &matrix)
bool LoadVertexSlices(C4GroupSet *pGroupSet, const char *szFile)
bool LoadFragmentSlices(C4GroupSet *pGroupSet, const char *szFile)
void AddDefine(const char *name)
void SetScriptCategories(const std::vector< std::string > &categories)
bool Init(const char *szWhat, const char **szUniforms, const char **szAttributes)
virtual bool Init(C4Window *pWindow, C4AbstractApp *pApp)
virtual bool Select(bool verbose=false)
std::vector< GLuint > hVAOs
static std::list< CStdGLCtx * > contexts
std::set< unsigned int > VAOIDs
C4Shader SpriteShaderLightBaseNormalMod2
void SetupMultiBlt(C4ShaderCall &call, const C4BltTransform *pTransform, GLuint baseTex, GLuint overlayTex, GLuint normalTex, DWORD dwOverlayModClr, StdProjectionMatrix *out_modelview)
unsigned int GenericVBOSizes[N_GENERIC_VBOS]
StdProjectionMatrix ProjectionMatrix
bool EnsureMainContextSelected() override
C4Shader SpriteShaderLightBase
C4Shader SpriteShaderBaseOverlayMod2
void PerformMultiBlt(C4Surface *sfcTarget, DrawOperation op, const C4BltVertex *vertices, unsigned int n_vertices, bool has_tex, C4ShaderCall *shader_call)
C4Shader SpriteShaderBaseOverlay
C4Shader SpriteShaderLightMod2
void ObjectLabel(uint32_t identifier, uint32_t name, int32_t length, const char *label)
bool InvalidateDeviceObjects() override
C4Shader SpriteShaderBaseMod2
unsigned int GenericVAOs[N_GENERIC_VBOS *2]
C4Shader SpriteShaderMod2
bool InitShaders(C4GroupSet *pGroups)
C4Shader SpriteShaderLightBaseNormal
const char * GLErrorString(GLenum code)
bool PrepareRendering(C4Surface *sfcToSurface) override
bool PrepareSpriteShader(C4Shader &shader, const char *name, int ssc, C4GroupSet *pGroups, const char *const *additionalDefines, const char *const *additionalSlices) override
GLuint GenericVBOs[N_GENERIC_VBOS]
bool CheckGLError(const char *szAtOp)
bool Error(const char *szMsg) override
static const unsigned int N_GENERIC_VBOS
void PerformMultiPix(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, C4ShaderCall *shader_call) override
C4Shader SpriteShaderLightBaseOverlay
void FillBG(DWORD dwClr=0) override
std::set< unsigned int >::iterator NextVAOID
C4Shader SpriteShaderLightBaseMod2
void FreeVAOID(unsigned int vaoid)
bool UpdateClipper() override
bool GetVAO(unsigned int vaoid, GLuint &vao)
C4Shader SpriteShaderBase
bool RestoreDeviceObjects() override
bool OnResolutionChanged(unsigned int iXRes, unsigned int iYRes) override
C4Shader SpriteShaderLightBaseNormalOverlay
C4Shader SpriteShaderLight
CStdGLCtx * CreateContext(C4Window *pWindow, C4AbstractApp *pApp) override
C4Shader * GetSpriteShader(int ssc)
void PerformMultiTris(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, const C4BltTransform *pTransform, C4TexRef *pTex, C4TexRef *pOverlay, C4TexRef *pNormal, DWORD dwOverlayClrMod, C4ShaderCall *shader_call) override
void PerformMultiLines(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, float width, C4ShaderCall *shader_call) override
C4Shader SpriteShaderLightBaseOverlayMod2
static const unsigned int GENERIC_VBO_SIZE
C4Shader SpriteShaderLightBaseNormalOverlayMod2
struct CStdGL::@10 Workarounds
static StdMeshMatrix Inverse(const StdMeshMatrix &mat)
static StdMeshMatrix Upper3x4(const StdProjectionMatrix &matrix)
static StdProjectionMatrix Translate(float dx, float dy, float dz)
static StdProjectionMatrix Identity()
static StdProjectionMatrix Orthographic(float left, float right, float bottom, float top)