local common = require "CommonStyle" local util = require "util" local my_style = {} my_style.header = {} my_style.source = {} ---------------------------------------------------- -- Global styling functions. function my_style.WriteLargeHeading(hFile, headingName) hFile:write(string.rep("/", 6 + #headingName), "\n") hFile:write("// ", headingName, "\n") hFile:write(string.rep("/", 6 + #headingName), "\n") end function my_style.WriteSmallHeading(hFile, headingName) hFile:write("// ", headingName, "\n") end ------------------------------------------------------ -- Header styling functions function my_style.header.GetFilename(basename, options) return basename .. ".hpp" end local function GenIncludeGuardName(hFile, spec, options) local str = "POINTER_CPP_GENERATED_HEADER" .. spec.GetIncludeGuardString() .. "_HPP" if(#options.prefix > 0) then return options.prefix:upper() .. "_" .. str end return str end function my_style.header.WriteBlockBeginIncludeGuard(hFile, spec, options) local inclGuard = GenIncludeGuardName(hFile, spec, options) hFile:fmt("#ifndef %s\n", inclGuard) hFile:fmt("#define %s\n", inclGuard) end function my_style.header.WriteBlockEndIncludeGuard(hFile, spec, options) hFile:fmt("#endif //%s\n", GenIncludeGuardName(hFile, spec, options)) end function my_style.header.WriteInit(hFile, spec, options) hFile:rawwrite(spec.GetHeaderInit()) end function my_style.header.WriteStdTypedefs(hFile, specData, spec, options) local defArray = common.GetStdTypedefs() hFile:write("#ifndef GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS\n") hFile:write("#define GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS\n") hFile:write("\n") hFile:inc() for _, def in ipairs(defArray) do hFile:write(def) end hFile:dec() hFile:write("\n") hFile:write("#endif /*GL_LOAD_GEN_BASIC_OPENGL_TYPEDEFS*/\n") end function my_style.header.WriteSpecTypedefs(hFile, specData, spec, options) hFile:push() common.WritePassthruData(hFile, specData.funcData.passthru) hFile:pop() end local function StartNamespace(hFile, namespaceName) hFile:fmt("namespace %s\n", namespaceName or "") hFile:write("{\n") hFile:inc() end local function EndNamespace(hFile, namespaceName) hFile:dec() hFile:fmt("} //namespace %s\n", namespaceName or "") end function my_style.header.WriteBlockBeginDecl(hFile, spec, options) if(#options.prefix > 0) then StartNamespace(hFile, options.prefix) end StartNamespace(hFile, spec.FuncNamePrefix()) end function my_style.header.WriteBlockEndDecl(hFile, spec, options) EndNamespace(hFile, spec.FuncNamePrefix()) if(#options.prefix > 0) then EndNamespace(hFile, options.prefix) end end local extBlockNamespace = "exts" local extVariableTypeDefinition = [[ class LoadTest { private: //Safe bool idiom. Joy! typedef void (LoadTest::*bool_type)() const; void big_long_name_that_really_doesnt_matter() const {} public: operator bool_type() const { return m_isLoaded ? &LoadTest::big_long_name_that_really_doesnt_matter : 0; } int GetNumMissing() const {return m_numMissing;} LoadTest() : m_isLoaded(false), m_numMissing(0) {} LoadTest(bool isLoaded, int numMissing) : m_isLoaded(isLoaded), m_numMissing(numMissing) {} private: bool m_isLoaded; int m_numMissing; }; ]] function my_style.header.WriteBlockBeginExtVarDecl(hFile, spec, options) StartNamespace(hFile, extBlockNamespace) hFile:writeblock(extVariableTypeDefinition) hFile:write("\n") end function my_style.header.WriteBlockEndExtVarDecl(hFile, spec, options) EndNamespace(hFile, extBlockNamespace) end local function GenExtensionVarName(extName, spec, options) return "var_" .. extName; end function my_style.header.WriteExtVariableDecl(hFile, extName, specData, spec, options) hFile:fmt("extern LoadTest %s;\n", GenExtensionVarName(extName, spec, options)); end function my_style.header.WriteBlockBeginEnumDecl(hFile, spec, options) hFile:write("enum\n") hFile:write("{\n") hFile:inc() end function my_style.header.WriteBlockEndEnumDecl(hFile, spec, options) hFile:dec() hFile:write("};\n") end local function GenEnumName(enum) return common.GetCppEnumName(enum) end function my_style.header.WriteEnumDecl(hFile, enum, enumTable, spec, options, enumSeen) if(enumSeen[enum.name]) then hFile:fmt("//%s taken from ext: %s\n", enum.name, enumSeen[enum.name]) else local enumName = GenEnumName(enum) local lenEnum = #enumName local numIndent = 33 local numSpaces = numIndent - lenEnum if(numSpaces < 1) then numSpaces = 1 end hFile:fmt("%s%s= %s,\n", enumName, string.rep(" ", numSpaces), common.ResolveEnumValue(enum, enumTable)) end end function my_style.header.WriteBlockBeginFuncDecl(hFile, spec, options) --Block containing all spec function declarations. end function my_style.header.WriteBlockEndFuncDecl(hFile, spec, options) --Block containing all spec function declarations. end function my_style.header.WriteBlockBeginExtFuncDecl(hFile, extName, spec, options) --Block containing all spec function declarations for a particular extension. --Useful for include-guards around extension function pointers. end function my_style.header.WriteBlockEndExtFuncDecl(hFile, extName, spec, options) --Block containing all spec function declarations for a particular extension. end local function GenFuncPtrName(func, spec, options) return func.name end local function GenFuncPtrTypedefName(func, spec, options) return "PFN" .. GenFuncPtrName(func, spec, options):upper() end local function WriteFuncPtrTypedefStmt(hFile, func, spec, options) hFile:fmt("typedef %s (%s *%s)(%s);\n", common.GetFuncReturnType(func), spec.GetCodegenPtrType(), GenFuncPtrTypedefName(func, spec, options), common.GetFuncParamList(func)) end local function GenFuncPtrDefDirect(func, spec, options) return string.format("%s (%s *%s)(%s)", common.GetFuncReturnType(func), spec.GetCodegenPtrType(), GenFuncPtrName(func, spec, options), common.GetFuncParamList(func, true)) end local function GenFuncPtrDefTypedef(func, spec, options) return string.format("%s %s", GenFuncPtrTypedefName(func, spec, options), GenFuncPtrName(func, spec, options)) end function my_style.header.WriteFuncDecl(hFile, func, spec, options) hFile:write("extern ", GenFuncPtrDefDirect(func, spec, options), ";\n") end function my_style.header.WriteBlockBeginSysDecl(hFile, spec, options) StartNamespace(hFile, "sys") end function my_style.header.WriteBlockEndSysDecl(hFile, spec, options) EndNamespace(hFile, "sys") end function my_style.header.WriteUtilityDecls(hFile, spec, options) --Write declarations for public utility stuff. Enums for return values, etc. end function my_style.header.WriteMainLoaderFuncDecl(hFile, spec, options) hFile:fmt("%s::LoadTest LoadFunctions(%s);\n", extBlockNamespace, spec.GetLoaderParams()) end function my_style.header.WriteVersioningFuncDecls(hFile, spec, options) hFile:writeblock([[ int GetMinorVersion(); int GetMajorVersion(); bool IsVersionGEQ(int majorVersion, int minorVersion); ]]) end -------------------------------------------------- -- Source code styling functions. function my_style.source.GetFilename(basename, options) return basename .. ".cpp" end function my_style.source.WriteIncludes(hFile, basename, spec, options) hFile:writeblock([[ #include #include #include #include ]]) local base = util.ParsePath(my_style.header.GetFilename(basename, options)) hFile:fmt('#include "%s"\n', base) end function my_style.source.WriteLoaderData(hFile, spec, options) hFile:writeblock(spec.GetLoaderFunc()) end function my_style.source.WriteBlockBeginDef(hFile, spec, options) if(#options.prefix > 0) then StartNamespace(hFile, options.prefix) end StartNamespace(hFile, spec.FuncNamePrefix()) end function my_style.source.WriteBlockEndDef(hFile, spec, options) EndNamespace(hFile, spec.FuncNamePrefix()) if(#options.prefix > 0) then EndNamespace(hFile, options.prefix) end end function my_style.source.WriteBlockBeginExtVarDef(hFile, spec, options) StartNamespace(hFile, extBlockNamespace) end function my_style.source.WriteBlockEndExtVarDef(hFile, spec, options) EndNamespace(hFile, extBlockNamespace) end function my_style.source.WriteExtVariableDef(hFile, extName, specData, spec, options) hFile:fmt("LoadTest %s;\n", GenExtensionVarName(extName, spec, options)); end function my_style.source.WriteBlockBeginExtFuncDef(hFile, extName, spec, options) --Block containing the extension function definitions and load function --for the functions in the extension `extName`. end function my_style.source.WriteBlockEndExtFuncDef(hFile, extName, spec, options) --Block containing the extension function definitions and load function --for the functions in the extension `extName`. end function my_style.source.WriteFuncDef(hFile, func, spec, options, funcSeen) if(not funcSeen[func.name]) then WriteFuncPtrTypedefStmt(hFile, func, spec, options) hFile:write(GenFuncPtrDefTypedef(func, spec, options), " = 0;\n") end end local function GenExtLoaderFuncName(extName, spec, options) return "Load_" .. extName; end function my_style.source.WriteBlockBeginExtLoader(hFile, extName, spec, options) hFile:fmt("static int %s()\n", GenExtLoaderFuncName(extName, spec, options)) hFile:write("{\n") hFile:inc() hFile:write("int numFailed = 0;\n") end function my_style.source.WriteBlockEndExtLoader(hFile, extName, spec, options) hFile:write "return numFailed;\n" hFile:dec() hFile:write("}\n") end function my_style.source.WriteExtFuncLoader(hFile, func, spec, options) hFile:fmt('%s = reinterpret_cast<%s>(%s("%s%s"));\n', GenFuncPtrName(func, spec, options), GenFuncPtrTypedefName(func, spec, options), common.GetProcAddressName(spec), spec.FuncNamePrefix(), func.name) hFile:fmt('if(!%s) ++numFailed;\n', GenFuncPtrName(func, spec, options)) end function my_style.source.WriteBlockBeginCoreFuncDef(hFile, version, spec, options) --Block containing the core functions for `version`. --The block also contains the loading function for this version. end function my_style.source.WriteBlockEndCoreFuncDef(hFile, version, spec, options) --Block containing the core functions for `version`. end local function GenCoreLoaderFuncName(version, spec, options) return "LoadCoreFunctions" end function my_style.source.WriteBlockBeginCoreLoader(hFile, version, spec, options) hFile:fmt("static int %s()\n", GenCoreLoaderFuncName(version, spec, options)) hFile:write("{\n") hFile:inc() hFile:write("int numFailed = 0;\n") end function my_style.source.WriteBlockEndCoreLoader(hFile, version, spec, options) hFile:write "return numFailed;\n" hFile:dec() hFile:write("}\n") end function my_style.source.WriteCoreFuncLoader(hFile, func, spec, options) hFile:fmt('%s = reinterpret_cast<%s>(%s("%s%s"));\n', GenFuncPtrName(func, spec, options), GenFuncPtrTypedefName(func, spec, options), common.GetProcAddressName(spec), spec.FuncNamePrefix(), func.name) --Special hack for DSA_EXT functions in core functions. --They do not count against the loaded count. if(func.name:match("EXT$")) then hFile:write("//An EXT_direct_state_access-based function. Don't count it if it fails to load.\n") else hFile:fmt('if(!%s) ++numFailed;\n', GenFuncPtrName(func, spec, options)) end end function my_style.source.WriteExtStringFuncDef(hFile, specData, spec, options, funcSeen) if(funcSeen[spec.GetExtStringFuncName()]) then return end --Check to see if its something we have to load. local function FindFuncName(funcName) for _, func in ipairs(specData.funcData.functions) do if(func.name == funcName) then return func end end return nil end local extStringFunc = FindFuncName(spec.GetExtStringFuncName()) if(extStringFunc) then hFile:write("\n") WriteFuncPtrTypedefStmt(hFile, extStringFunc, spec, options) hFile:write("static ", GenFuncPtrDefTypedef(extStringFunc, spec, options), " = 0;\n") hFile:write("\n") end end function my_style.source.WriteBlockBeginSysDef(hFile, spec, options) StartNamespace(hFile, "sys") end function my_style.source.WriteBlockEndSysDef(hFile, spec, options) EndNamespace(hFile, "sys") end function my_style.source.WriteUtilityDefs(hFile, specData, spec, options) --Write our mapping table definitions. StartNamespace(hFile) hFile:writeblock[[ typedef int (*PFN_LOADEXTENSION)(); struct MapEntry { MapEntry(const char *_extName, exts::LoadTest *_extVariable) : extName(_extName) , extVariable(_extVariable) , loaderFunc(0) {} MapEntry(const char *_extName, exts::LoadTest *_extVariable, PFN_LOADEXTENSION _loaderFunc) : extName(_extName) , extVariable(_extVariable) , loaderFunc(_loaderFunc) {} const char *extName; exts::LoadTest *extVariable; PFN_LOADEXTENSION loaderFunc; }; struct MapCompare { MapCompare(const char *test_) : test(test_) {} bool operator()(const MapEntry &other) { return strcmp(test, other.extName) == 0; } const char *test; }; ]] --Write the table initialization function. hFile:write "void InitializeMappingTable(std::vector &table)\n" hFile:write "{\n" hFile:inc() hFile:fmt("table.reserve(%i);\n", #options.extensions) for _, extName in ipairs(options.extensions) do if(#specData.extdefs[extName].funcs > 0) then hFile:fmt('table.push_back(MapEntry("%s", &exts::%s, %s));\n', spec.ExtNamePrefix() .. extName, GenExtensionVarName(extName, spec, options), GenExtLoaderFuncName(extName, spec, options)) else hFile:fmt('table.push_back(MapEntry("%s", &exts::%s));\n', spec.ExtNamePrefix() .. extName, GenExtensionVarName(extName, spec, options)) end end hFile:dec() hFile:write "}\n" hFile:write "\n" --Write the function to clear the extension variables. hFile:fmt("void ClearExtensionVars()\n") hFile:write("{\n") hFile:inc() for _, extName in ipairs(options.extensions) do hFile:fmt('exts::%s = exts::LoadTest();\n', GenExtensionVarName(extName, spec, options)) end hFile:dec() hFile:write("}\n") hFile:write "\n" --Write a function that loads an extension by name. It is called when --processing, so it should also set the extension variable based on the load. hFile:writeblock([[ void LoadExtByName(std::vector &table, const char *extensionName) { std::vector::iterator entry = std::find_if(table.begin(), table.end(), MapCompare(extensionName)); if(entry != table.end()) { if(entry->loaderFunc) (*entry->extVariable) = exts::LoadTest(true, entry->loaderFunc()); else (*entry->extVariable) = exts::LoadTest(true, 0); } } ]]) EndNamespace(hFile) hFile:write "\n" end local function GenQualifier(spec, options) local ret = "" if(#options.prefix > 0) then ret = options.prefix .. "::" end ret = ret .. spec.FuncNamePrefix() .. "::" return ret end local function GenQualifiedEnumName(enum, spec, options) return GenQualifier(spec, options) .. GenEnumName(enum, spec, options) end local function GenQualifiedFuncPtrName(func, spec, options) return GenQualifier(spec, options) .. GenFuncPtrName(func, spec, options) end local function WriteAncillaryFuncs(hFile, specData, spec, options) local indexed = spec.GetIndexedExtStringFunc(options); if(indexed) then for _, func in ipairs(specData.funcData.functions) do if(indexed[1] == func.name) then indexed[1] = func end if(indexed[3] == func.name) then indexed[3] = func end end for _, enum in ipairs(specData.enumerators) do if(indexed[2] == enum.name) then indexed[2] = enum end if(indexed[4] == enum.name) then indexed[4] = enum end end hFile:writeblock([[ static void ProcExtsFromExtList(std::vector &table) { GLint iLoop; GLint iNumExtensions = 0; ]] .. GenQualifiedFuncPtrName(indexed[1], spec, options) .. [[(]] .. GenQualifiedEnumName(indexed[2], spec, options) .. [[, &iNumExtensions); for(iLoop = 0; iLoop < iNumExtensions; iLoop++) { const char *strExtensionName = (const char *)]] .. GenQualifiedFuncPtrName(indexed[3], spec, options) .. [[(]] .. GenQualifiedEnumName(indexed[4], spec, options) .. [[, iLoop); LoadExtByName(table, strExtensionName); } } ]]) else hFile:writeblock(common.GetProcessExtsFromStringFunc( "LoadExtByName(table, %s)", ", std::vector &table")) end hFile:write "\n" return indexed end local function WriteInMainFuncLoader(hFile, func, spec, options) hFile:fmt('%s = reinterpret_cast<%s>(%s("%s%s"));\n', GenFuncPtrName(func, spec, options), GenFuncPtrTypedefName(func, spec, options), common.GetProcAddressName(spec), spec.FuncNamePrefix(), func.name) hFile:fmt('if(!%s) return exts::LoadTest();\n', GenFuncPtrName(func, spec, options)) end function my_style.source.WriteMainLoaderFunc(hFile, specData, spec, options) StartNamespace(hFile) local indexed = WriteAncillaryFuncs(hFile, specData, spec, options) EndNamespace(hFile) hFile:write "\n" hFile:fmt("exts::LoadTest LoadFunctions(%s)\n", spec.GetLoaderParams()) hFile:write("{\n") hFile:inc() hFile:writeblock[[ ClearExtensionVars(); std::vector table; InitializeMappingTable(table); ]] hFile:write("\n") if(indexed) then WriteInMainFuncLoader(hFile, indexed[1], spec, options) WriteInMainFuncLoader(hFile, indexed[3], spec, options) hFile:write("\n") hFile:write("ProcExtsFromExtList(table);\n") else local extListName, needLoad = spec.GetExtStringFuncName() if(needLoad) then for _, func in ipairs(specData.funcData.functions) do if(extListName == func.name) then extListName = func break end end WriteInMainFuncLoader(hFile, extListName, spec, options) extListName = GenQualifiedFuncPtrName(extListName, spec, options); end local function EnumResolve(enumName) return GenQualifiedEnumName(specData.enumtable[enumName], spec, options) end hFile:write "\n" hFile:fmt("ProcExtsFromExtString((const char *)%s(%s), table);\n", extListName, spec.GetExtStringParamList(EnumResolve)) end if(options.version) then hFile:write "\n" hFile:fmt("int numFailed = %s();\n", GenCoreLoaderFuncName(options.version, spec, options)) hFile:write("return exts::LoadTest(true, numFailed);\n") else hFile:fmt("return exts::LoadTest(true, 0);\n") end hFile:dec() hFile:write("}\n") end function my_style.source.WriteVersioningFuncs(hFile, specData, spec, options) hFile:fmt("static int g_major_version = 0;\n") hFile:fmt("static int g_minor_version = 0;\n") hFile:write "\n" if(tonumber(options.version) >= 3.0) then hFile:writeblock([[ static void GetGLVersion() { GetIntegerv(MAJOR_VERSION, &g_major_version); GetIntegerv(MINOR_VERSION, &g_minor_version); } ]]) else hFile:writeblock(common.GetParseVersionFromString()) hFile:write "\n" hFile:writeblock([[ static void GetGLVersion() { ParseVersionFromString(&g_major_version, &g_minor_version, GetString(VERSION)); } ]]) end hFile:write "\n" hFile:writeblock([[ int GetMajorVersion() { if(g_major_version == 0) GetGLVersion(); return g_major_version; } ]]) hFile:write "\n" hFile:writeblock([[ int GetMinorVersion() { if(g_major_version == 0) //Yes, check the major version to get the minor one. GetGLVersion(); return g_minor_version; } ]]) hFile:write "\n" hFile:writeblock([[ bool IsVersionGEQ(int majorVersion, int minorVersion) { if(g_major_version == 0) GetGLVersion(); if(majorVersion > g_major_version) return true; if(majorVersion < g_major_version) return false; if(minorVersion >= g_minor_version) return true; return false; } ]]) end -------------------------------------------------- -- Style retrieval machinery local function Create() return common.DeepCopyTable(my_style), common.GetStandardStructure() end return { Create = Create }