Advertisement
Guest User

The shitty GL function loader

a guest
Jun 7th, 2016
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.05 KB | None | 0 0
  1. // readme.txt
  2.  
  3. yo dawg.
  4.  
  5. This is some minimal OpenGL header and loader generator.
  6. It does *not* include the default GL.h piece of shit.
  7. You have to include all typedefs and tokens you use by yourself.
  8.  
  9. 1. Create C# command line app named Glue.
  10. 2. Copy Program.cs to the project.
  11. 3. Compile that shit.
  12. 4. Check example.cmd and example.txt below for usage.
  13.  
  14. And fuck nope, it isn't really tested.
  15.  
  16. Cheers, E1.
  17.  
  18. // Program.cs
  19.  
  20. using System;
  21. using System.Collections.Generic;
  22. using System.IO;
  23. using System.Text;
  24.  
  25. namespace Glue
  26. {
  27. /// <summary>
  28. /// List of strings.
  29. /// </summary>
  30. class StringList : LinkedList<String>
  31. {
  32. /// <summary>
  33. /// Creates a new list.
  34. /// </summary>
  35. public StringList()
  36. : base()
  37. {
  38. }
  39.  
  40. /// <summary>
  41. /// Creates a new list.
  42. /// </summary>
  43. /// <param name="tokens">Token array.</param>
  44. public StringList(String[] tokens)
  45. : base(tokens)
  46. {
  47. }
  48.  
  49. /// <summary>
  50. /// Pops the first element.
  51. /// </summary>
  52. /// <returns>First element.</returns>
  53. public String PopFirst()
  54. {
  55. var result = First.Value;
  56. RemoveFirst();
  57.  
  58. return result;
  59. }
  60.  
  61. /// <summary>
  62. /// Pops the last element.
  63. /// </summary>
  64. /// <returns>Last element.</returns>
  65. public String PopLast()
  66. {
  67. var result = Last.Value;
  68. RemoveLast();
  69.  
  70. return result;
  71. }
  72. }
  73.  
  74. /// <summary>
  75. /// Generator base entry.
  76. /// </summary>
  77. /// <typeparam name="N">Type of the name.</typeparam>
  78. /// <typeparam name="D">Type of the data.</typeparam>
  79. class Entry<N, D>
  80. {
  81. /// <summary>
  82. /// Entry name.
  83. /// </summary>
  84. public N Name;
  85.  
  86. /// <summary>
  87. /// Entry data.
  88. /// </summary>
  89. public D Data;
  90.  
  91. /// <summary>
  92. /// Creates a new entry.
  93. /// </summary>
  94. /// <param name="name">Entry name.</param>
  95. /// <param name="data">Entry data.</param>
  96. public Entry(N name, D data)
  97. {
  98. Name = name;
  99. Data = data;
  100. }
  101. }
  102.  
  103. /// <summary>
  104. /// Named generator entry.
  105. /// </summary>
  106. class Named : Entry<String, StringList>
  107. {
  108. /// <summary>
  109. /// Joined typename cache.
  110. /// </summary>
  111. private String joined;
  112.  
  113. /// <summary>
  114. /// Creates a new named entry.
  115. /// </summary>
  116. /// <param name="name">Entry name.</param>
  117. /// <param name="data">Entry data.</param>
  118. public Named(String name, StringList data)
  119. : base(name, data)
  120. {
  121. }
  122.  
  123. /// <summary>
  124. /// Joins the data into a typename.
  125. /// </summary>
  126. /// <returns>Typename.</returns>
  127. public String Join()
  128. {
  129. if (joined == null)
  130. {
  131. StringBuilder builder = new StringBuilder();
  132. foreach (var token in Data)
  133. {
  134. if (token.Equals("*") || builder.Length == 0)
  135. builder.Append(token);
  136. else
  137. builder.Append(" ").Append(token);
  138. }
  139.  
  140. joined = builder.ToString();
  141. }
  142.  
  143. return joined;
  144. }
  145. }
  146.  
  147. /// <summary>
  148. /// Generator function entry.
  149. /// </summary>
  150. class Function : Entry<Named, List<Named>>
  151. {
  152. /// <summary>
  153. /// Entry point array index.
  154. /// </summary>
  155. public int Index;
  156.  
  157. /// <summary>
  158. /// Creates a new function entry.
  159. /// </summary>
  160. /// <param name="name">Function name.</param>
  161. /// <param name="data">Function data.</param>
  162. /// <param name="index">Entry point array index.</param>
  163. public Function(Named name, List<Named> data, int index)
  164. : base(name, data)
  165. {
  166. Index = index;
  167. }
  168.  
  169. /// <summary>
  170. /// Test void return.
  171. /// </summary>
  172. /// <returns>True on success.</returns>
  173. public bool IsVoid()
  174. {
  175. var data = Name.Data;
  176. return data.Count == 1 && (data.First.Value.Equals("void") || data.First.Value.Equals("GLvoid"));
  177. }
  178. }
  179.  
  180. /// <summary>
  181. /// OpenGL extension loader generator.
  182. /// </summary>
  183. class Generator
  184. {
  185. /// <summary>
  186. /// Current file while parsing.
  187. /// </summary>
  188. private String file;
  189.  
  190. /// <summary>
  191. /// Line number while parsing.
  192. /// </summary>
  193. private int current;
  194.  
  195. /// <summary>
  196. /// Dynamic linkage for functions.
  197. /// </summary>
  198. private bool dynamic;
  199.  
  200. /// <summary>
  201. /// Current entry point array index.
  202. /// </summary>
  203. private int index;
  204.  
  205. /// <summary>
  206. /// OpenGL constant tokens.
  207. /// </summary>
  208. private List<Named> constants = new List<Named>();
  209.  
  210. /// <summary>
  211. /// OpenGL type definitions.
  212. /// </summary>
  213. private List<String> types = new List<String>();
  214.  
  215. /// <summary>
  216. /// OpenGL function definitions.
  217. /// </summary>
  218. private List<Function> functions = new List<Function>();
  219.  
  220. /// <summary>
  221. /// Adds a new file to the generator.
  222. /// </summary>
  223. /// <param name="file">Extension file name.</param>
  224. public void Add(String file)
  225. {
  226. // Reset parser state.
  227. this.file = file; current = 0; dynamic = false;
  228.  
  229. // Parse template file.
  230. using (var reader = new StreamReader(file))
  231. {
  232. while (true)
  233. {
  234. current++;
  235.  
  236. String line = reader.ReadLine();
  237. if (line == null)
  238. break;
  239.  
  240. int index = line.IndexOf("//");
  241. if (index != -1)
  242. line = line.Substring(0, index);
  243.  
  244. line = line.Trim();
  245. if (line.Length == 0)
  246. continue;
  247.  
  248. if (StartsWith(line, "#pragma"))
  249. {
  250. var tokens = Split(line, null);
  251. if (tokens.Count != 2)
  252. Panic("invalid #pragma");
  253.  
  254. tokens.RemoveFirst();
  255. var action = tokens.PopFirst();
  256.  
  257. if (action.Equals("dynamic"))
  258. dynamic = true;
  259. else if (action.Equals("static"))
  260. dynamic = false;
  261. else
  262. Panic("invalid pragma directive");
  263.  
  264. continue;
  265. }
  266.  
  267. if (StartsWith(line, "#define"))
  268. {
  269. ParseConstant(line);
  270. continue;
  271. }
  272.  
  273. if (line.EndsWith(";"))
  274. line = line.Substring(0, line.Length - 1).Trim();
  275.  
  276. if (line.Length == 0)
  277. continue;
  278.  
  279. if (StartsWith(line, "typedef"))
  280. {
  281. line = line.Substring(7, line.Length - 7).Trim();
  282. if (line.Length == 0)
  283. Panic("invalid typedef");
  284.  
  285. types.Add(line);
  286. continue;
  287. }
  288.  
  289. line = line.Replace("*", " * ").Trim();
  290. if (line.Length == 0)
  291. continue;
  292.  
  293. ParseFunction(line);
  294. }
  295. }
  296. }
  297.  
  298. /// <summary>
  299. /// Writes the header file.
  300. /// </summary>
  301. /// <param name="writer">Destination stream.</param>
  302. public void WriteHeader(StreamWriter writer)
  303. {
  304. writer.WriteLine("#pragma once");
  305. writer.WriteLine();
  306. writer.WriteLine("#include <stddef.h>");
  307. writer.WriteLine("#include <stdint.h>");
  308. writer.WriteLine();
  309. writer.WriteLine("#ifndef GLAPI");
  310. writer.WriteLine("#define GLAPI extern \"C\" __declspec(dllimport)");
  311. writer.WriteLine("#endif");
  312. writer.WriteLine();
  313. writer.WriteLine("#ifndef GLAPIENTRY");
  314. writer.WriteLine("#define GLAPIENTRY __stdcall");
  315. writer.WriteLine("#endif");
  316. writer.WriteLine();
  317. writer.WriteLine("#pragma comment (lib, \"OPENGL32\")");
  318. writer.WriteLine();
  319. if (index > 0)
  320. {
  321. writer.WriteLine("// Load function pointers.");
  322. writer.WriteLine("extern void LoadGL();");
  323. writer.WriteLine();
  324. }
  325.  
  326. // Emit types.
  327. if (types.Count > 0)
  328. {
  329. foreach (var type in types)
  330. writer.WriteLine("typedef " + type + ";");
  331.  
  332. writer.WriteLine();
  333. }
  334.  
  335. // Emit constants.
  336. if (constants.Count > 0)
  337. {
  338. foreach (var constant in constants)
  339. writer.WriteLine("#define " + Pad(constant.Name, 60) + " " + constant.Join());
  340.  
  341. writer.WriteLine();
  342. }
  343.  
  344. // Direct (static) imports.
  345. int direct = 0;
  346. foreach (var function in functions)
  347. {
  348. if (function.Index == -1)
  349. direct++;
  350. }
  351.  
  352. // Emit direct imports.
  353. if (direct > 0)
  354. {
  355. foreach (var function in functions)
  356. {
  357. if (function.Index != -1)
  358. continue;
  359.  
  360. var name = function.Name;
  361. var data = function.Data;
  362.  
  363. writer.Write("GLAPI " + name.Join() + " GLAPIENTRY " + name.Name + " (");
  364. for (int i = 0, n = data.Count; i < n; i++)
  365. {
  366. if (i > 0)
  367. writer.Write(", ");
  368.  
  369. writer.Write(data[i].Join() + " " + data[i].Name);
  370. }
  371. writer.WriteLine(");");
  372. }
  373.  
  374. writer.WriteLine();
  375. }
  376.  
  377. // Emit dynamic imports.
  378. if (index > 0)
  379. {
  380. foreach (var function in functions)
  381. {
  382. if (function.Index == -1)
  383. continue;
  384.  
  385. writer.WriteLine("#define " + Pad("IDX" + function.Name.Name.ToUpper() + "PROC", 60) + " " + function.Index);
  386. }
  387.  
  388. writer.WriteLine();
  389.  
  390. writer.WriteLine("// OpenGL function pointers.");
  391. writer.WriteLine("extern void* PFNGL[" + index + "];");
  392. writer.WriteLine();
  393.  
  394. int count = 0;
  395. foreach (var function in functions)
  396. {
  397. if (function.Index == -1)
  398. continue;
  399.  
  400. var name = function.Name;
  401. var data = function.Data;
  402.  
  403. writer.Write("inline " + name.Join() + " " + name.Name + " (");
  404. for (int i = 0, n = data.Count; i < n; i++)
  405. {
  406. if (i > 0)
  407. writer.Write(", ");
  408.  
  409. writer.Write(data[i].Join() + " " + data[i].Name);
  410. }
  411.  
  412. writer.WriteLine(") {");
  413. writer.Write(" ");
  414.  
  415. if (!function.IsVoid())
  416. writer.Write("return ");
  417.  
  418. writer.Write("((" + name.Join() + " (GLAPIENTRY *)(");
  419. for (int i = 0, n = data.Count; i < n; i++)
  420. {
  421. if (i > 0)
  422. writer.Write(", ");
  423.  
  424. writer.Write(data[i].Join());
  425. }
  426. writer.Write(")) PFNGL[" + function.Index + "]) (");
  427. for (int i = 0, n = data.Count; i < n; i++)
  428. {
  429. if (i > 0)
  430. writer.Write(", ");
  431.  
  432. writer.Write(data[i].Name);
  433. }
  434. writer.WriteLine(");");
  435. writer.WriteLine("}");
  436.  
  437. // Be a Newline-Nazi!
  438. if (++count < index)
  439. writer.WriteLine();
  440. }
  441. }
  442.  
  443. Console.WriteLine(types.Count + " types.");
  444. Console.WriteLine(constants.Count + " constants.");
  445. Console.WriteLine(functions.Count + " functions (" + (functions.Count - index) + " static, " + index + " dynamic).");
  446. }
  447.  
  448. /// <summary>
  449. /// Writes the source file.
  450. /// </summary>
  451. /// <param name="writer">Destination stream.</param>
  452. public void WriteSource(StreamWriter writer)
  453. {
  454. if (index == 0)
  455. {
  456. writer.WriteLine("// There may be dragons.");
  457. writer.WriteLine("// Nothing to generate.");
  458. return;
  459. }
  460.  
  461. writer.WriteLine("#include <Windows.h>");
  462. writer.WriteLine();
  463. writer.WriteLine("// Function pointers.");
  464. writer.WriteLine("void* PFNGL[" + index + "];");
  465. writer.WriteLine();
  466. writer.WriteLine("// Function names.");
  467. writer.WriteLine("static const char* names[" + index + "] = {");
  468.  
  469. foreach (var function in functions)
  470. {
  471. if (function.Index == -1)
  472. continue;
  473.  
  474. writer.WriteLine(" \"" + function.Name.Name + "\",");
  475. }
  476.  
  477. writer.WriteLine("};");
  478. writer.WriteLine();
  479. writer.WriteLine("// Load function pointers.");
  480. writer.WriteLine("void LoadGL() {");
  481. writer.WriteLine(" for (int i = 0; i < " + index + "; i++) {");
  482. writer.WriteLine(" PFNGL[i] = wglGetProcAddress(names[i]);");
  483. writer.WriteLine(" }");
  484. writer.WriteLine("}");
  485. }
  486.  
  487. /// <summary>
  488. /// Parses a single constant.
  489. /// </summary>
  490. /// <param name="line">Current line.</param>
  491. private void ParseConstant(String line)
  492. {
  493. var tokens = Split(line, null);
  494. if (tokens.Count < 3)
  495. Panic("invalid #define");
  496.  
  497. tokens.RemoveFirst();
  498. constants.Add(new Named(tokens.PopFirst(), tokens));
  499. }
  500.  
  501. /// <summary>
  502. /// Parses a named parameter.
  503. /// </summary>
  504. /// <param name="line">Current line.</param>
  505. /// <returns>Named parmeter.</returns>
  506. private Named ParseNamed(String line)
  507. {
  508. var tokens = Split(line, null);
  509. if (tokens.Count < 2)
  510. Panic("invalid type and name");
  511.  
  512. return new Named(tokens.PopLast(), tokens);
  513. }
  514.  
  515. /// <summary>
  516. /// Parses a function entry point.
  517. /// </summary>
  518. /// <param name="line">Current line.</param>
  519. private void ParseFunction(String line)
  520. {
  521. int lp = line.IndexOf("(");
  522. int rp = line.IndexOf(")");
  523. if (lp == -1 || rp == -1 || rp < lp)
  524. Panic("invalid function prototype");
  525.  
  526. var name = ParseNamed(line.Substring(0, lp));
  527. var data = new List<Named>();
  528.  
  529. var guard = false;
  530. foreach (var token in Split(line.Substring(lp + 1, rp - lp - 1), ","))
  531. {
  532. if (token.Equals("void") || token.Equals("GLvoid"))
  533. {
  534. if (data.Count > 0)
  535. Panic("invalid usage of void or GLvoid");
  536.  
  537. guard = true;
  538. }
  539. else
  540. {
  541. if (guard)
  542. Panic("additional parameters after void or GLvoid");
  543.  
  544. data.Add(ParseNamed(token));
  545. }
  546. }
  547.  
  548. functions.Add(new Function(name, data, dynamic ? index++ : -1));
  549. }
  550.  
  551. /// <summary>
  552. /// Throws an annotated error.
  553. /// </summary>
  554. /// <param name="msg">Error message.</param>
  555. private void Panic(String msg)
  556. {
  557. throw new ApplicationException(file + " [" + current + "] " + msg);
  558. }
  559.  
  560. /// <summary>
  561. /// Splits a string into components.
  562. /// </summary>
  563. /// <param name="line">Current line.</param>
  564. /// <param name="delimiters">Optional delimiters.</param>
  565. /// <returns></returns>
  566. private static StringList Split(String line, String delimiters)
  567. {
  568. var tokens = line.Split(delimiters == null ? null : delimiters.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  569.  
  570. var result = new StringList();
  571. foreach (var token in tokens)
  572. result.AddLast(token.Trim());
  573.  
  574. return result;
  575. }
  576.  
  577. /// <summary>
  578. /// String prefix test.
  579. /// </summary>
  580. /// <param name="line">Current line.</param>
  581. /// <param name="prefix">Prefix value.</param>
  582. /// <returns>True on success.</returns>
  583. private static bool StartsWith(String line, String prefix)
  584. {
  585. if (line.StartsWith(prefix))
  586. return line.Length == prefix.Length || Char.IsWhiteSpace(line[prefix.Length]);
  587.  
  588. return false;
  589. }
  590.  
  591. /// <summary>
  592. /// Pad string to length.
  593. /// </summary>
  594. /// <param name="what">String to pad.</param>
  595. /// <param name="count">Result count.</param>
  596. /// <returns>Padded string.</returns>
  597. private static String Pad(String what, int count)
  598. {
  599. StringBuilder builder = new StringBuilder(what);
  600. for (int i = 0, n = count - what.Length; i < n; i++)
  601. builder.Append(" ");
  602.  
  603. return builder.ToString();
  604. }
  605. }
  606.  
  607. class Program
  608. {
  609. static void Main(string[] args)
  610. {
  611. if (args.Length == 0)
  612. {
  613. Console.WriteLine("Usage: Glue [template] [name]");
  614. Console.WriteLine();
  615. Console.WriteLine("Parses the [template] and outputs [name].hpp and [name].cpp OpenGL function loader.");
  616. Console.WriteLine("Use #pragma static|dynamic to toggle desired linkage.");
  617. Console.WriteLine("Initial state when parsing a template is static.");
  618. Console.WriteLine();
  619. Console.WriteLine("This is intended for 64K intros, so have fun!");
  620. Console.WriteLine("Hakuna Matata, EvilOne");
  621. Environment.Exit(0);
  622. }
  623.  
  624. if (args.Length < 2)
  625. {
  626. Console.Error.WriteLine("invalid command line arguments");
  627. Environment.Exit(1);
  628. }
  629.  
  630. try
  631. {
  632. Generator generator = new Generator();
  633.  
  634. for (int i = 0; i < args.Length - 1; i++)
  635. generator.Add(args[i]);
  636.  
  637. using (StreamWriter writer = new StreamWriter(args[args.Length - 1] + ".hpp"))
  638. generator.WriteHeader(writer);
  639.  
  640. using (StreamWriter writer = new StreamWriter(args[args.Length - 1] + ".cpp"))
  641. generator.WriteSource(writer);
  642.  
  643. Environment.Exit(0);
  644. }
  645. catch (Exception e)
  646. {
  647. Console.Error.WriteLine(e.Message);
  648. Environment.Exit(1);
  649. }
  650. }
  651. }
  652. }
  653.  
  654. // example.cmd
  655.  
  656. @echo off
  657.  
  658. Glue
  659. echo.
  660.  
  661. Glue example.txt example
  662. echo.
  663.  
  664. pause
  665.  
  666. // example.txt
  667.  
  668. typedef unsigned int GLenum;
  669. typedef unsigned char GLboolean;
  670. typedef unsigned int GLbitfield;
  671. typedef signed char GLbyte;
  672. typedef short GLshort;
  673. typedef int GLint;
  674. typedef int GLsizei;
  675. typedef unsigned char GLubyte;
  676. typedef unsigned short GLushort;
  677. typedef unsigned int GLuint;
  678. typedef float GLfloat;
  679. typedef float GLclampf;
  680. typedef double GLdouble;
  681. typedef double GLclampd;
  682. typedef void GLvoid;
  683. typedef char GLchar;
  684. typedef ptrdiff_t GLintptr;
  685. typedef ptrdiff_t GLsizeiptr;
  686.  
  687. #define GL_FRAGMENT_SHADER 0x8B30
  688. #define GL_VERTEX_SHADER 0x8B31
  689. #define GL_GEOMETRY_SHADER 0x8DD9
  690.  
  691. #pragma static
  692.  
  693. void glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
  694. void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
  695.  
  696. #pragma dynamic
  697.  
  698. void glCompileShader (GLuint shader);
  699. GLuint glCreateProgram (void);
  700. GLuint glCreateShader (GLenum type);
  701. void glDeleteProgram (GLuint program);
  702. void glDeleteShader (GLuint shader);
  703. void glDetachShader (GLuint program, GLuint shader);
  704. void glGetProgramiv (GLuint program, GLenum pname, GLint *params);
  705. void glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
  706. void glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
  707. void glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
  708. void glLinkProgram (GLuint program);
  709. void glShaderSource (GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length);
  710. void glUseProgram (GLuint program);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement