#define GDRAW_ASSERTS #include "../../../Windows64/Iggy/include/iggy.h" #include "../../../Windows64/Iggy/include/gdraw.h" #include "gdraw.h" #include #include #include #include #include #include #include #include #include #include #define true 1 #define false 0 #ifndef _ENABLEIGGY void* IggyGDrawMallocAnnotated(SINTa size, const char* file, int line) { (void)file; (void)line; return malloc((size_t)size); } void IggyGDrawFree(void* ptr) { free(ptr); } void IggyGDrawSendWarning(Iggy* f, char const* message, ...) { (void)f; va_list args; va_start(args, message); fprintf(stderr, "[Iggy GDraw Warning] "); vfprintf(stderr, message, args); fprintf(stderr, "\n"); va_end(args); } void IggyDiscardVertexBufferCallback(void* owner, void* buf) { (void)owner; (void)buf; } #endif static void* get_gl_proc(const char* name) { void* p = SDL_GL_GetProcAddress(name); if (!p) p = dlsym(RTLD_DEFAULT, name); if (!p) { char buf[256]; strncpy(buf, name, sizeof(buf) - 1); buf[255] = '\0'; char* ext = strstr(buf, "ARB"); if (!ext) ext = strstr(buf, "EXT"); if (ext && ext == buf + strlen(buf) - 3) { *ext = '\0'; p = SDL_GL_GetProcAddress(buf); if (!p) p = dlsym(RTLD_DEFAULT, buf); } } return p; } #define GDRAW_GL_EXTENSION_LIST \ /* identifier import procname */ \ /* GL_ARB_vertex_buffer_object */ \ GLE(GenBuffers, "GenBuffersARB", GENBUFFERSARB) \ GLE(DeleteBuffers, "DeleteBuffersARB", DELETEBUFFERSARB) \ GLE(BindBuffer, "BindBufferARB", BINDBUFFERARB) \ GLE(BufferData, "BufferDataARB", BUFFERDATAARB) \ GLE(MapBuffer, "MapBufferARB", MAPBUFFERARB) \ GLE(UnmapBuffer, "UnmapBufferARB", UNMAPBUFFERARB) \ GLE(VertexAttribPointer, "VertexAttribPointerARB", VERTEXATTRIBPOINTERARB) \ GLE(EnableVertexAttribArray, "EnableVertexAttribArrayARB", \ ENABLEVERTEXATTRIBARRAYARB) \ GLE(DisableVertexAttribArray, "DisableVertexAttribArrayARB", \ DISABLEVERTEXATTRIBARRAYARB) \ /* GL_ARB_shader_objects */ \ GLE(CreateShader, "CreateShaderObjectARB", CREATESHADEROBJECTARB) \ GLE(DeleteShader, "DeleteObjectARB", DELETEOBJECTARB) \ GLE(ShaderSource, "ShaderSourceARB", SHADERSOURCEARB) \ GLE(CompileShader, "CompileShaderARB", COMPILESHADERARB) \ GLE(GetShaderiv, "GetObjectParameterivARB", GETOBJECTPARAMETERIVARB) \ GLE(GetShaderInfoLog, "GetInfoLogARB", GETINFOLOGARB) \ GLE(CreateProgram, "CreateProgramObjectARB", CREATEPROGRAMOBJECTARB) \ GLE(DeleteProgram, "DeleteObjectARB", DELETEOBJECTARB) \ GLE(AttachShader, "AttachObjectARB", ATTACHOBJECTARB) \ GLE(LinkProgram, "LinkProgramARB", LINKPROGRAMARB) \ GLE(GetUniformLocation, "GetUniformLocationARB", GETUNIFORMLOCATIONARB) \ GLE(UseProgram, "UseProgramObjectARB", USEPROGRAMOBJECTARB) \ GLE(GetProgramiv, "GetObjectParameterivARB", GETOBJECTPARAMETERIVARB) \ GLE(GetProgramInfoLog, "GetInfoLogARB", GETINFOLOGARB) \ GLE(Uniform1i, "Uniform1iARB", UNIFORM1IARB) \ GLE(Uniform4f, "Uniform4fARB", UNIFORM4FARB) \ GLE(Uniform4fv, "Uniform4fvARB", UNIFORM4FVARB) \ /* GL_ARB_vertex_shader */ \ GLE(BindAttribLocation, "BindAttribLocationARB", BINDATTRIBLOCATIONARB) \ /* Missing from WGL but needed by shared code */ \ GLE(Uniform1f, "Uniform1fARB", UNIFORM1FARB) \ /* GL_EXT_framebuffer_object */ \ GLE(GenRenderbuffers, "GenRenderbuffersEXT", GENRENDERBUFFERSEXT) \ GLE(DeleteRenderbuffers, "DeleteRenderbuffersEXT", DELETERENDERBUFFERSEXT) \ GLE(BindRenderbuffer, "BindRenderbufferEXT", BINDRENDERBUFFEREXT) \ GLE(RenderbufferStorage, "RenderbufferStorageEXT", RENDERBUFFERSTORAGEEXT) \ GLE(GenFramebuffers, "GenFramebuffersEXT", GENFRAMEBUFFERSEXT) \ GLE(DeleteFramebuffers, "DeleteFramebuffersEXT", DELETEFRAMEBUFFERSEXT) \ GLE(BindFramebuffer, "BindFramebufferEXT", BINDFRAMEBUFFEREXT) \ GLE(CheckFramebufferStatus, "CheckFramebufferStatusEXT", \ CHECKFRAMEBUFFERSTATUSEXT) \ GLE(FramebufferRenderbuffer, "FramebufferRenderbufferEXT", \ FRAMEBUFFERRENDERBUFFEREXT) \ GLE(FramebufferTexture2D, "FramebufferTexture2DEXT", \ FRAMEBUFFERTEXTURE2DEXT) \ GLE(GenerateMipmap, "GenerateMipmapEXT", GENERATEMIPMAPEXT) \ /* GL_EXT_framebuffer_blit */ \ GLE(BlitFramebuffer, "BlitFramebufferEXT", BLITFRAMEBUFFEREXT) \ /* GL_EXT_framebuffer_multisample */ \ GLE(RenderbufferStorageMultisample, "RenderbufferStorageMultisampleEXT", \ RENDERBUFFERSTORAGEMULTISAMPLEEXT) \ /* */ // Shared .inl #define gdraw_GLx_(id) gdraw_GL_##id #define GDRAW_GLx_(id) GDRAW_GL_##id #define GDRAW_SHADERS "gdraw_gl_shaders.inl" // GLhandleARB is void* but shader functions use GLuint values. // homework stolen from gdraw_gl_shared.inl. #define GDrawGLProgram GLuint typedef GLuint GLhandle; typedef gdraw_gl_resourcetype gdraw_resourcetype; #define GLE(id, import, procname) static PFNGL##procname##PROC gl##id; GDRAW_GL_EXTENSION_LIST #undef GLE typedef const GLubyte*(APIENTRYP PFNGLGETSTRINGIPROC_)(GLenum name, GLuint index); static PFNGLGETSTRINGIPROC_ gdraw_glGetStringi = NULL; typedef void(APIENTRYP PFNGLGENVERTEXARRAYSPROC_)(GLsizei n, GLuint* arrays); typedef void(APIENTRYP PFNGLBINDVERTEXARRAYPROC_)(GLuint array); static PFNGLGENVERTEXARRAYSPROC_ gdraw_glGenVertexArrays = NULL; static PFNGLBINDVERTEXARRAYPROC_ gdraw_glBindVertexArray = NULL; static GLuint gdraw_vao = 0; typedef void(APIENTRYP gdraw_vtxattrib_fn)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void*); static gdraw_vtxattrib_fn gdraw_real_vtxattrib = NULL; static GLuint gdraw_screenvbo = 0; static const void* gdraw_screenvbo_base = NULL; static size_t gdraw_expected_vbo_size = 0; typedef void(APIENTRYP gdraw_drawelements_fn)(GLenum mode, GLsizei count, GLenum type, const void* indices); static gdraw_drawelements_fn gdraw_real_drawelements = NULL; static GLuint gdraw_screenibo = 0; typedef GLuint(APIENTRYP gdraw_createshader_fn)(GLenum); typedef void(APIENTRYP gdraw_shadersource_fn)(GLuint, GLsizei, const GLchar**, const GLint*); typedef void(APIENTRYP gdraw_compileshader_fn)(GLuint); typedef void(APIENTRYP gdraw_linkprogram_fn)(GLuint); static gdraw_createshader_fn gdraw_real_createshader = NULL; static gdraw_shadersource_fn gdraw_real_shadersource = NULL; static gdraw_compileshader_fn gdraw_real_compileshader = NULL; static gdraw_linkprogram_fn gdraw_real_linkprogram = NULL; // some core reject p0 typedef void(APIENTRYP gdraw_useprogram_fn)(GLuint); static gdraw_useprogram_fn gdraw_real_useprogram = NULL; static GLuint gdraw_null_program = 0; typedef void(APIENTRYP gdraw_teximage2d_fn)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void*); typedef void(APIENTRYP gdraw_texsubimage2d_fn)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void*); static gdraw_teximage2d_fn gdraw_real_teximage2d = NULL; static gdraw_texsubimage2d_fn gdraw_real_texsubimage2d = NULL; #define TRY(ptr, arb, core) \ do { \ void* _p = get_gl_proc(core); \ if (!_p) _p = get_gl_proc(arb); \ *(void**)&(ptr) = _p; \ } while (0) static void load_extensions(void) { // gl_shared requires ts shit ugh #define GLE(id, import, procname) \ gl##id = (PFNGL##procname##PROC)get_gl_proc("gl" import); GDRAW_GL_EXTENSION_LIST #undef GLE TRY(glCreateShader, "glCreateShaderObjectARB", "glCreateShader"); TRY(glDeleteShader, "glDeleteObjectARB", "glDeleteShader"); TRY(glShaderSource, "glShaderSourceARB", "glShaderSource"); TRY(glCompileShader, "glCompileShaderARB", "glCompileShader"); TRY(glGetShaderiv, "glGetObjectParameterivARB", "glGetShaderiv"); TRY(glGetShaderInfoLog, "glGetInfoLogARB", "glGetShaderInfoLog"); TRY(glCreateProgram, "glCreateProgramObjectARB", "glCreateProgram"); TRY(glDeleteProgram, "glDeleteObjectARB", "glDeleteProgram"); TRY(glAttachShader, "glAttachObjectARB", "glAttachShader"); TRY(glLinkProgram, "glLinkProgramARB", "glLinkProgram"); TRY(glGetUniformLocation, "glGetUniformLocationARB", "glGetUniformLocation"); TRY(glUseProgram, "glUseProgramObjectARB", "glUseProgram"); TRY(glGetProgramiv, "glGetObjectParameterivARB", "glGetProgramiv"); TRY(glGetProgramInfoLog, "glGetInfoLogARB", "glGetProgramInfoLog"); TRY(glUniform1i, "glUniform1iARB", "glUniform1i"); TRY(glUniform4f, "glUniform4fARB", "glUniform4f"); TRY(glUniform4fv, "glUniform4fvARB", "glUniform4fv"); TRY(glUniform1f, "glUniform1fARB", "glUniform1f"); TRY(glBindAttribLocation, "glBindAttribLocationARB", "glBindAttribLocation"); TRY(glGenBuffers, "glGenBuffersARB", "glGenBuffers"); TRY(glDeleteBuffers, "glDeleteBuffersARB", "glDeleteBuffers"); TRY(glBindBuffer, "glBindBufferARB", "glBindBuffer"); TRY(glBufferData, "glBufferDataARB", "glBufferData"); TRY(glMapBuffer, "glMapBufferARB", "glMapBuffer"); TRY(glUnmapBuffer, "glUnmapBufferARB", "glUnmapBuffer"); TRY(glVertexAttribPointer, "glVertexAttribPointerARB", "glVertexAttribPointer"); TRY(glEnableVertexAttribArray, "glEnableVertexAttribArrayARB", "glEnableVertexAttribArray"); TRY(glDisableVertexAttribArray, "glDisableVertexAttribArrayARB", "glDisableVertexAttribArray"); TRY(glGenRenderbuffers, "glGenRenderbuffersEXT", "glGenRenderbuffers"); TRY(glDeleteRenderbuffers, "glDeleteRenderbuffersEXT", "glDeleteRenderbuffers"); TRY(glBindRenderbuffer, "glBindRenderbufferEXT", "glBindRenderbuffer"); TRY(glRenderbufferStorage, "glRenderbufferStorageEXT", "glRenderbufferStorage"); TRY(glGenFramebuffers, "glGenFramebuffersEXT", "glGenFramebuffers"); TRY(glDeleteFramebuffers, "glDeleteFramebuffersEXT", "glDeleteFramebuffers"); TRY(glBindFramebuffer, "glBindFramebufferEXT", "glBindFramebuffer"); TRY(glCheckFramebufferStatus, "glCheckFramebufferStatusEXT", "glCheckFramebufferStatus"); TRY(glFramebufferRenderbuffer, "glFramebufferRenderbufferEXT", "glFramebufferRenderbuffer"); TRY(glFramebufferTexture2D, "glFramebufferTexture2DEXT", "glFramebufferTexture2D"); TRY(glGenerateMipmap, "glGenerateMipmapEXT", "glGenerateMipmap"); TRY(glBlitFramebuffer, "glBlitFramebufferEXT", "glBlitFramebuffer"); TRY(glRenderbufferStorageMultisample, "glRenderbufferStorageMultisampleEXT", "glRenderbufferStorageMultisample"); // Save raw pointers before we #define over the names below gdraw_real_vtxattrib = (gdraw_vtxattrib_fn)get_gl_proc("glVertexAttribPointer"); gdraw_real_createshader = (gdraw_createshader_fn)get_gl_proc("glCreateShader"); gdraw_real_shadersource = (gdraw_shadersource_fn)get_gl_proc("glShaderSource"); gdraw_real_compileshader = (gdraw_compileshader_fn)get_gl_proc("glCompileShader"); gdraw_real_linkprogram = (gdraw_linkprogram_fn)get_gl_proc("glLinkProgram"); gdraw_real_teximage2d = (gdraw_teximage2d_fn)get_gl_proc("glTexImage2D"); gdraw_real_texsubimage2d = (gdraw_texsubimage2d_fn)get_gl_proc("glTexSubImage2D"); gdraw_real_useprogram = (gdraw_useprogram_fn)get_gl_proc("glUseProgram"); gdraw_real_drawelements = (gdraw_drawelements_fn)get_gl_proc("glDrawElements"); gdraw_glGetStringi = (PFNGLGETSTRINGIPROC_)get_gl_proc("glGetStringi"); gdraw_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC_)get_gl_proc("glGenVertexArrays"); gdraw_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC_)get_gl_proc("glBindVertexArray"); if (gdraw_glGenVertexArrays && gdraw_glBindVertexArray && gdraw_vao == 0) { gdraw_glGenVertexArrays(1, &gdraw_vao); gdraw_glBindVertexArray(gdraw_vao); } } #undef TRY // rebind vbo static void clear_renderstate_platform_specific(void) { if (gdraw_glBindVertexArray && gdraw_vao) gdraw_glBindVertexArray(gdraw_vao); } static void error_msg_platform_specific(const char* msg) { fprintf(stderr, "[GDraw] %s\n", msg); } #define GDRAW_PLATFORM_REPORT_GL_SITE(site) \ do { \ if ((site) != NULL) \ fprintf(stderr, "[GDraw] GL error site: %s\n", (site)); \ } while (0) #define GDRAW_MULTISAMPLING // i wish i could improve this function #ifdef RR_BREAK #undef RR_BREAK #endif #define RR_BREAK() \ do { \ fprintf(stderr, "[GDraw] GL error at %s:%d\n", __FILE__, __LINE__); \ } while (0) // the magic number that tropical told me #define GDRAW_MAX_SHADERS 64 static struct { GLuint handle; GLenum type; } gdraw_shader_types[GDRAW_MAX_SHADERS]; static int gdraw_shader_type_count = 0; static GLenum gdraw_get_shader_type(GLuint shader) { for (int i = 0; i < gdraw_shader_type_count; i++) if (gdraw_shader_types[i].handle == shader) return gdraw_shader_types[i].type; return GL_FRAGMENT_SHADER; } static GLuint gdraw_CreateShaderTracked(GLenum type) { GLuint h = gdraw_real_createshader(type); if (h && gdraw_shader_type_count < GDRAW_MAX_SHADERS) { gdraw_shader_types[gdraw_shader_type_count].handle = h; gdraw_shader_types[gdraw_shader_type_count].type = type; gdraw_shader_type_count++; } return h; } static void gdraw_CompileShaderAndLog(GLuint shader) { GLint status = 0; gdraw_real_compileshader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &status); if (!status) { char log[2048]; GLint len = 0; glGetShaderInfoLog(shader, (GLsizei)sizeof(log) - 1, &len, log); log[len] = '\0'; fprintf(stderr, "[GDraw GLSL] compile FAILED shader=%u:\n%s\n", shader, log); } } static void gdraw_LinkProgramAndLog(GLuint program) { GLint status = 0; gdraw_real_linkprogram(program); glGetProgramiv(program, GL_LINK_STATUS, &status); if (!status) { char log[2048]; GLint len = 0; glGetProgramInfoLog(program, (GLsizei)sizeof(log) - 1, &len, log); log[len] = '\0'; fprintf(stderr, "[GDraw GLSL] link FAILED program=%u:\n%s\n", program, log); } } #undef glCreateShader #define glCreateShader gdraw_CreateShaderTracked // This is the part that turns the old ugly shaders to 330 static char* gdraw_strreplace(char* src, const char* find, const char* rep) { char* result; char* pos; char* base = src; size_t find_len = strlen(find); size_t rep_len = strlen(rep); size_t count = 0; char* tmp = src; while ((tmp = strstr(tmp, find))) { count++; tmp += find_len; } if (!count) return src; result = (char*)malloc(strlen(src) + count * (rep_len + 1) + 1); if (!result) return src; tmp = result; while ((pos = strstr(src, find))) { size_t before = (size_t)(pos - src); memcpy(tmp, src, before); tmp += before; memcpy(tmp, rep, rep_len); tmp += rep_len; src = pos + find_len; } strcpy(tmp, src); free(base); return result; } static void gdraw_ShaderSourceUpgraded(GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths) { size_t total = 0; for (int i = 0; i < count; i++) total += lengths ? (lengths[i] >= 0 ? (size_t)lengths[i] : strlen(strings[i])) : strlen(strings[i]); char* src = (char*)malloc(total + 1); if (!src) { gdraw_real_shadersource(shader, count, strings, lengths); return; } src[0] = '\0'; for (int i = 0; i < count; i++) { size_t len = lengths ? (lengths[i] >= 0 ? (size_t)lengths[i] : strlen(strings[i])) : strlen(strings[i]); strncat(src, strings[i], len); } int is_vert = (gdraw_get_shader_type(shader) == GL_VERTEX_SHADER); // Strip any existing #version directive as i'll add our own { char* vp = strstr(src, "#version"); if (vp) { char* nl = strchr(vp, '\n'); if (nl) memmove(vp, nl + 1, strlen(nl + 1) + 1); else *vp = '\0'; } } // Texture built-ins src = gdraw_strreplace(src, "texture2DRect", "texture"); src = gdraw_strreplace(src, "texture2D", "texture"); // Attribute -> in src = gdraw_strreplace(src, "attribute ", "in "); src = gdraw_strreplace(src, "attribute\t", "in\t"); src = gdraw_strreplace(src, "attribute\n", "in\n"); // Varying -> out (vert) / in (frag) if (is_vert) { src = gdraw_strreplace(src, "varying ", "out "); src = gdraw_strreplace(src, "varying\t", "out\t"); src = gdraw_strreplace(src, "varying\n", "out\n"); } else { src = gdraw_strreplace(src, "varying ", "in "); src = gdraw_strreplace(src, "varying\t", "in\t"); src = gdraw_strreplace(src, "varying\n", "in\n"); src = gdraw_strreplace(src, "gl_FragData[0]", "_gdraw_frag_out"); src = gdraw_strreplace(src, "gl_FragColor", "_gdraw_frag_out"); } const char* header = is_vert ? "#version 330 core\n" : "#version 330 core\nout vec4 _gdraw_frag_out;\n"; char* patched = (char*)malloc(strlen(header) + strlen(src) + 2); if (!patched) { free(src); gdraw_real_shadersource(shader, count, strings, lengths); return; } strcpy(patched, header); strcat(patched, src); free(src); const GLchar* patched_ptr = (const GLchar*)patched; gdraw_real_shadersource(shader, 1, &patched_ptr, NULL); free(patched); } #undef glShaderSource #define glShaderSource gdraw_ShaderSourceUpgraded // Remap all the deprecated internal formats to their modern equivalents // (idk why but just the word "swizzle" is cracking me up) static void gdraw_apply_swizzle(GLenum internal_fmt) { if (internal_fmt == 0x1906 /* GL_ALPHA */ || internal_fmt == GL_RED) { GLint sw[4] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED}; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, sw); } else if (internal_fmt == 0x1909 /* GL_LUMINANCE */) { GLint sw[4] = {GL_RED, GL_RED, GL_RED, GL_ONE}; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, sw); } else if (internal_fmt == 0x190A /* GL_LUMINANCE_ALPHA */) { GLint sw[4] = {GL_RED, GL_RED, GL_RED, GL_GREEN}; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, sw); } } static GLenum gdraw_remap_fmt(GLenum fmt) { switch (fmt) { case 0x1906: return GL_RED; // GL_ALPHA case 0x1909: return GL_RED; // GL_LUMINANCE case 0x190A: return GL_RG; // GL_LUMINANCE_ALPHA case 0x8033: return GL_RG; // GL_LUMINANCE4_ALPHA4 case 0x8045: return GL_R8; // GL_LUMINANCE8 case 0x8048: return GL_RG8; // GL_LUMINANCE8_ALPHA8 case 0x804F: return GL_R8; // GL_INTENSITY4 case 0x8050: return GL_R8; // GL_INTENSITY8 default: return fmt; } } static void gdraw_TexImage2D(GLenum target, GLint level, GLint ifmt, GLsizei w, GLsizei h, GLint border, GLenum fmt, GLenum type, const void* data) { // ES strictly requires explicitly sized formats & stuff if (ifmt == GL_RGBA && data == NULL) ifmt = GL_RGBA8; GLenum new_ifmt = gdraw_remap_fmt((GLenum)ifmt); GLenum new_fmt = gdraw_remap_fmt(fmt); gdraw_real_teximage2d(target, level, (GLint)new_ifmt, w, h, border, new_fmt, type, data); if (new_ifmt != (GLenum)ifmt) gdraw_apply_swizzle((GLenum)ifmt); } static void gdraw_TexSubImage2D(GLenum target, GLint level, GLint xoff, GLint yoff, GLsizei w, GLsizei h, GLenum fmt, GLenum type, const void* data) { GLenum new_fmt = gdraw_remap_fmt(fmt); gdraw_real_texsubimage2d(target, level, xoff, yoff, w, h, new_fmt, type, data); } #undef glTexImage2D #define glTexImage2D gdraw_TexImage2D #undef glTexSubImage2D #define glTexSubImage2D gdraw_TexSubImage2D // vbo emu static void gdraw_ClientVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) { if (gdraw_glBindVertexArray && gdraw_vao) { GLint current_vao = 0; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, ¤t_vao); if ((GLuint)current_vao != gdraw_vao) gdraw_glBindVertexArray(gdraw_vao); } GLint current_vbo = 0; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_vbo); if (current_vbo != 0 && current_vbo != (GLint)gdraw_screenvbo) { // no touchies gdraw_real_vtxattrib(index, size, type, normalized, stride, pointer); return; } if (pointer == NULL) { gdraw_real_vtxattrib(index, size, type, normalized, stride, pointer); return; } ptrdiff_t offset = gdraw_screenvbo_base ? ((const char*)pointer - (const char*)gdraw_screenvbo_base) : -1; if (gdraw_screenvbo_base == NULL || offset < 0 || offset >= (ptrdiff_t)gdraw_expected_vbo_size) { if (!gdraw_screenvbo) glGenBuffers(1, &gdraw_screenvbo); glBindBuffer(GL_ARRAY_BUFFER, gdraw_screenvbo); size_t upload_size = gdraw_expected_vbo_size > 0 ? (gdraw_expected_vbo_size + 256) : 65536; glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)upload_size, pointer, GL_STREAM_DRAW); gdraw_screenvbo_base = pointer; gdraw_real_vtxattrib(index, size, type, normalized, stride, (const void*)0); } else { glBindBuffer(GL_ARRAY_BUFFER, gdraw_screenvbo); gdraw_real_vtxattrib(index, size, type, normalized, stride, (const void*)offset); } } #undef glVertexAttribPointer #define glVertexAttribPointer gdraw_ClientVertexAttribPointer // fake ibo static void hooked_glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { GLint current_ibo = 0; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ¤t_ibo); if (current_ibo == 0 && indices != NULL) { if (!gdraw_screenibo) glGenBuffers(1, &gdraw_screenibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gdraw_screenibo); size_t index_size = (type == GL_UNSIGNED_SHORT) ? 2 : (type == GL_UNSIGNED_BYTE) ? 1 : 4; glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(count * index_size), indices, GL_STREAM_DRAW); gdraw_real_drawelements(mode, count, type, (const void*)0); } else { gdraw_real_drawelements(mode, count, type, indices); } } #define glDrawElements hooked_glDrawElements // dummy shader for glUseProgram(0) safety static void gdraw_UseProgramSafe(GLuint program) { if (!program) { if (!gdraw_null_program && gdraw_real_useprogram) { const char* vs = "#version 330 core\nvoid main(){gl_Position=vec4(0);}"; const char* fs = "#version 330 core\nout vec4 c;\nvoid main(){c=vec4(0);}"; GLuint v = gdraw_real_createshader(GL_VERTEX_SHADER); GLuint f = gdraw_real_createshader(GL_FRAGMENT_SHADER); gdraw_real_shadersource(v, 1, &vs, NULL); gdraw_real_shadersource(f, 1, &fs, NULL); gdraw_real_compileshader(v); gdraw_real_compileshader(f); gdraw_null_program = glCreateProgram(); glAttachShader(gdraw_null_program, v); glAttachShader(gdraw_null_program, f); gdraw_real_linkprogram(gdraw_null_program); glDeleteShader(v); glDeleteShader(f); } gdraw_real_useprogram(gdraw_null_program); return; } gdraw_real_useprogram(program); } #undef glUseProgram #define glUseProgram gdraw_UseProgramSafe #undef glCompileShader #define glCompileShader gdraw_CompileShaderAndLog #undef glLinkProgram #define glLinkProgram gdraw_LinkProgramAndLog static void gdraw_FramebufferRenderbufferSafe(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { static GLuint last_depth_rb = 0; if (attachment == GL_DEPTH_ATTACHMENT) { last_depth_rb = renderbuffer; (glFramebufferRenderbuffer)(target, attachment, renderbuffertarget, renderbuffer); } else if (attachment == GL_STENCIL_ATTACHMENT) { if (renderbuffer == last_depth_rb && renderbuffer != 0) { // If identical, bind as packed depth-stencil to satisfy strict GLES // ^ how greedy -n- (glFramebufferRenderbuffer)( target, 0x821A /* GL_DEPTH_STENCIL_ATTACHMENT */, renderbuffertarget, renderbuffer); } else { (glFramebufferRenderbuffer)(target, attachment, renderbuffertarget, renderbuffer); } } else { (glFramebufferRenderbuffer)(target, attachment, renderbuffertarget, renderbuffer); } } #define glFramebufferRenderbuffer_SAFE gdraw_FramebufferRenderbufferSafe #define glFramebufferRenderbuffer glFramebufferRenderbuffer_SAFE #include "../../../Windows64/Iggy/gdraw/gdraw_gl_shared.inl" #undef glVertexAttribPointer #define glVertexAttribPointer gdraw_real_vtxattrib static int hasext_core(const char* name) { GLint n = 0; if (!gdraw_glGetStringi) return 0; glGetIntegerv(GL_NUM_EXTENSIONS, &n); for (GLint i = 0; i < n; i++) { const char* e = (const char*)gdraw_glGetStringi(GL_EXTENSIONS, (GLuint)i); if (e && strcmp(e, name) == 0) return 1; } return 0; } static gdraw_draw_indexed_triangles* real_DrawIndexedTriangles = NULL; static void RADLINK hooked_DrawIndexedTriangles(GDrawRenderState* r, GDrawPrimitive* prim, GDrawVertexBuffer* buf, GDrawStats* stats) { if (buf == NULL && prim != NULL && prim->vertices != NULL) { size_t stride = 8; if (prim->vertex_format == GDRAW_vformat_v2aa) stride = 16; else if (prim->vertex_format == GDRAW_vformat_v2tc2) stride = 16; else if (prim->vertex_format == GDRAW_vformat_ihud1) stride = 20; gdraw_expected_vbo_size = prim->num_vertices * stride; } else { gdraw_expected_vbo_size = 0; } gdraw_screenvbo_base = NULL; // Force VBO re-upload for each primitive real_DrawIndexedTriangles(r, prim, buf, stats); } static gdraw_filter_quad* real_FilterQuad = NULL; static void RADLINK hooked_FilterQuad(GDrawRenderState* r, S32 x0, S32 y0, S32 x1, S32 y1, GDrawStats* stats) { gdraw_expected_vbo_size = 4 * 20; // 4 vertices, max stride gdraw_screenvbo_base = NULL; real_FilterQuad(r, x0, y0, x1, y1, stats); } static gdraw_rendering_begin* real_RenderingBegin = NULL; // stupid hack static void RADLINK hooked_RenderingBegin(void) { if (real_RenderingBegin) real_RenderingBegin(); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); OPENGL_CHECK_SITE("hooked_RenderingBegin:post_state"); } // Creating the context GDrawFunctions* gdraw_GL_CreateContext(S32 w, S32 h, S32 msaa_samples) { static const TextureFormatDesc tex_formats[] = { {IFT_FORMAT_rgba_8888, 1, 1, 4, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, {IFT_FORMAT_rgba_4444_LE, 1, 1, 2, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, {IFT_FORMAT_rgba_5551_LE, 1, 1, 2, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, {IFT_FORMAT_la_88, 1, 1, 2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, {IFT_FORMAT_la_44, 1, 1, 1, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, {IFT_FORMAT_i_8, 1, 1, 1, GL_INTENSITY8, GL_ALPHA, GL_UNSIGNED_BYTE}, {IFT_FORMAT_i_4, 1, 1, 1, GL_INTENSITY4, GL_ALPHA, GL_UNSIGNED_BYTE}, {IFT_FORMAT_l_8, 1, 1, 1, GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE}, {IFT_FORMAT_l_4, 1, 1, 1, GL_LUMINANCE4, GL_LUMINANCE, GL_UNSIGNED_BYTE}, {IFT_FORMAT_DXT1, 4, 4, 8, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0, GL_UNSIGNED_BYTE}, {IFT_FORMAT_DXT3, 4, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0, GL_UNSIGNED_BYTE}, {IFT_FORMAT_DXT5, 4, 4, 16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0, GL_UNSIGNED_BYTE}, {0, 0, 0, 0, 0, 0, 0}, }; GLint major = 0, minor = 0; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor); if (major < 3) { fprintf(stderr, "[GDraw] GL 3.0 or higher required (got %d.%d)\n", major, minor); return NULL; } load_extensions(); if (gdraw_glBindVertexArray && gdraw_vao) gdraw_glBindVertexArray(gdraw_vao); GDrawFunctions* funcs = create_context(w, h); if (!funcs) return NULL; // hook the vtable entries for VBO reset and render state real_DrawIndexedTriangles = funcs->DrawIndexedTriangles; funcs->DrawIndexedTriangles = hooked_DrawIndexedTriangles; real_FilterQuad = funcs->FilterQuad; funcs->FilterQuad = hooked_FilterQuad; real_RenderingBegin = funcs->RenderingBegin; funcs->RenderingBegin = hooked_RenderingBegin; funcs->ClearID = gdraw_ClearID; gdraw->tex_formats = tex_formats; gdraw->has_mapbuffer = false; gdraw->has_depth24 = true; gdraw->has_texture_max_level = true; gdraw->has_packed_depth_stencil = true; GLint n = 0; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &n); gdraw->has_conditional_non_power_of_two = (n < 8192); if (msaa_samples > 1) { glGetIntegerv(GL_MAX_SAMPLES, &n); gdraw->multisampling = RR_MIN(msaa_samples, n); } opengl_check(); fprintf(stderr, "[GDraw] Context created successfully (%dx%d, msaa=%d)\n", w, h, msaa_samples); return funcs; } // Custom draw callbacks void gdraw_GL_BeginCustomDraw_4J(IggyCustomDrawCallbackRegion* region, F32* matrix) { // rebind vbo if (gdraw_glBindVertexArray && gdraw_vao) gdraw_glBindVertexArray(gdraw_vao); clear_renderstate(); gdraw_GetObjectSpaceMatrix(matrix, region->o2w, gdraw->projection, depth_from_id(0), 0); } void gdraw_GL_CalculateCustomDraw_4J(IggyCustomDrawCallbackRegion* region, F32* matrix) { gdraw_GetObjectSpaceMatrix(matrix, region->o2w, gdraw->projection, 0.0f, 0); }