PageRenderTime 127ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/gl.cpp

https://bitbucket.org/Themaister/libretro-gl
C++ | 538 lines | 433 code | 101 blank | 4 comment | 15 complexity | 3c50ba4d3a3e84fe87ebf0e0ea633fdd MD5 | raw file
  1. #include "libretro.h"
  2. #include <stdint.h>
  3. #include <string.h>
  4. #include <math.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <algorithm>
  8. #include <string>
  9. #include "rpng/rpng.h"
  10. #include <glm/glm.hpp>
  11. #include <glm/gtc/matrix_transform.hpp>
  12. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  13. static struct retro_hw_render_callback hw_render;
  14. using namespace glm;
  15. #define GL_GLEXT_PROTOTYPES
  16. #if defined(GLES)
  17. #include <GLES3/gl3.h>
  18. #include <GLES2/gl2ext.h>
  19. #else
  20. #include <GL/glew.h>
  21. #include <GL/gl.h>
  22. #endif
  23. static std::string texpath;
  24. static GLuint prog;
  25. static GLuint vao;
  26. static GLuint vbo, mbo;
  27. static GLuint ibo;
  28. static GLuint tex;
  29. static bool update;
  30. static vec3 player_pos;
  31. static float camera_rot_x;
  32. static float camera_rot_y;
  33. struct Vertex
  34. {
  35. GLfloat vert[4];
  36. GLfloat normal[4];
  37. GLfloat tex[2];
  38. };
  39. static const Vertex vertex_data[] = {
  40. { { -1, -1, -1, 1 }, { 0, 0, -1, 0 }, { 0, 0 } }, // Front
  41. { { 1, -1, -1, 1 }, { 0, 0, -1, 0 }, { 1, 0 } },
  42. { { -1, 1, -1, 1 }, { 0, 0, -1, 0 }, { 0, 1 } },
  43. { { 1, 1, -1, 1 }, { 0, 0, -1, 0 }, { 1, 1 } },
  44. { { 1, -1, 1, 1 }, { 0, 0, 1, 0 }, { 0, 0 } }, // Back
  45. { { -1, -1, 1, 1 }, { 0, 0, 1, 0 }, { 1, 0 } },
  46. { { 1, 1, 1, 1 }, { 0, 0, 1, 0 }, { 0, 1 } },
  47. { { -1, 1, 1, 1 }, { 0, 0, 1, 0 }, { 1, 1 } },
  48. { { -1, -1, 1, 1 }, { -1, 0, 0, 0 }, { 0, 0 } }, // Left
  49. { { -1, -1, -1, 1 }, { -1, 0, 0, 0 }, { 1, 0 } },
  50. { { -1, 1, 1, 1 }, { -1, 0, 0, 0 }, { 0, 1 } },
  51. { { -1, 1, -1, 1 }, { -1, 0, 0, 0 }, { 1, 1 } },
  52. { { 1, -1, -1, 1 }, { 1, 0, 0, 0 }, { 0, 0 } }, // Right
  53. { { 1, -1, 1, 1 }, { 1, 0, 0, 0 }, { 1, 0 } },
  54. { { 1, 1, -1, 1 }, { 1, 0, 0, 0 }, { 0, 1 } },
  55. { { 1, 1, 1, 1 }, { 1, 0, 0, 0 }, { 1, 1 } },
  56. { { -1, 1, -1, 1 }, { 0, 1, 0, 0 }, { 0, 0 } }, // Top
  57. { { 1, 1, -1, 1 }, { 0, 1, 0, 0 }, { 1, 0 } },
  58. { { -1, 1, 1, 1 }, { 0, 1, 0, 0 }, { 0, 1 } },
  59. { { 1, 1, 1, 1 }, { 0, 1, 0, 0 }, { 1, 1 } },
  60. { { -1, -1, 1, 1 }, { 0, -1, 0, 0 }, { 0, 0 } }, // Bottom
  61. { { 1, -1, 1, 1 }, { 0, -1, 0, 0 }, { 1, 0 } },
  62. { { -1, -1, -1, 1 }, { 0, -1, 0, 0 }, { 0, 1 } },
  63. { { 1, -1, -1, 1 }, { 0, -1, 0, 0 }, { 1, 1 } },
  64. };
  65. static const GLubyte indices[] = {
  66. 0, 1, 2, // Front
  67. 3, 2, 1,
  68. 4, 5, 6, // Back
  69. 7, 6, 5,
  70. 8, 9, 10, // Left
  71. 11, 10, 9,
  72. 12, 13, 14, // Right
  73. 15, 14, 13,
  74. 16, 17, 18, // Top
  75. 19, 18, 17,
  76. 20, 21, 22, // Bottom
  77. 23, 22, 21,
  78. };
  79. static const char *vertex_shader[] = {
  80. "uniform mat4 uVP;",
  81. "uniform mat4 uM;",
  82. "attribute vec4 aVertex;",
  83. "attribute vec4 aNormal;",
  84. "attribute vec2 aTexCoord;",
  85. "attribute vec4 aOffset;",
  86. "varying vec3 normal;",
  87. "varying vec4 model_pos;",
  88. "varying vec2 tex_coord;",
  89. "void main() {",
  90. " model_pos = uM * (aVertex + aOffset);",
  91. " gl_Position = uVP * model_pos;",
  92. " vec4 trans_normal = uM * aNormal;",
  93. " normal = trans_normal.xyz;",
  94. " tex_coord = aTexCoord;",
  95. "}",
  96. };
  97. static const char *fragment_shader[] = {
  98. "varying vec3 normal;",
  99. "varying vec4 model_pos;",
  100. "varying vec2 tex_coord;",
  101. "uniform vec3 light_pos;",
  102. "uniform vec4 ambient_light;",
  103. "uniform sampler2D uTexture;",
  104. "void main() {",
  105. " vec3 diff = light_pos - model_pos.xyz;",
  106. " float dist_mod = 100.0 * inversesqrt(dot(diff, diff));",
  107. " gl_FragColor = texture2D(uTexture, tex_coord) * (ambient_light + dist_mod * smoothstep(0.0, 1.0, dot(normalize(diff), normal)));",
  108. "}",
  109. };
  110. static void print_shader_log(GLuint shader)
  111. {
  112. GLsizei len = 0;
  113. glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
  114. if (!len)
  115. return;
  116. char *buffer = new char[len];
  117. glGetShaderInfoLog(shader, len, &len, buffer);
  118. fprintf(stderr, "Info Log: %s\n", buffer);
  119. delete[] buffer;
  120. }
  121. static void compile_program(void)
  122. {
  123. prog = glCreateProgram();
  124. GLuint vert = glCreateShader(GL_VERTEX_SHADER);
  125. GLuint frag = glCreateShader(GL_FRAGMENT_SHADER);
  126. glShaderSource(vert, ARRAY_SIZE(vertex_shader), vertex_shader, 0);
  127. glShaderSource(frag, ARRAY_SIZE(fragment_shader), fragment_shader, 0);
  128. glCompileShader(vert);
  129. glCompileShader(frag);
  130. int status = 0;
  131. glGetShaderiv(vert, GL_COMPILE_STATUS, &status);
  132. if (!status)
  133. {
  134. fprintf(stderr, "Vertex shader failed to compile!\n");
  135. print_shader_log(vert);
  136. }
  137. glGetShaderiv(frag, GL_COMPILE_STATUS, &status);
  138. if (!status)
  139. {
  140. fprintf(stderr, "Fragment shader failed to compile!\n");
  141. print_shader_log(frag);
  142. }
  143. glAttachShader(prog, vert);
  144. glAttachShader(prog, frag);
  145. glLinkProgram(prog);
  146. glGetProgramiv(prog, GL_LINK_STATUS, &status);
  147. if (!status)
  148. fprintf(stderr, "Program failed to link!\n");
  149. }
  150. #define CUBE_SIZE 32
  151. static void setup_vao(void)
  152. {
  153. glUseProgram(prog);
  154. //glGenVertexArrays(1, &vao);
  155. //glBindVertexArray(vao);
  156. glGenBuffers(1, &vbo);
  157. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  158. glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
  159. glGenBuffers(1, &mbo);
  160. glBindBuffer(GL_ARRAY_BUFFER, mbo);
  161. glBufferData(GL_ARRAY_BUFFER, CUBE_SIZE * CUBE_SIZE * CUBE_SIZE * sizeof(GLfloat) * 4, NULL, GL_STREAM_DRAW);
  162. glGenBuffers(1, &ibo);
  163. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  164. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
  165. glBindBuffer(GL_ARRAY_BUFFER, 0);
  166. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  167. glUseProgram(0);
  168. update = true;
  169. }
  170. static GLuint load_texture(const char *path)
  171. {
  172. uint32_t *data;
  173. unsigned width, height;
  174. if (!rpng_load_image_argb(path, &data, &width, &height))
  175. {
  176. fprintf(stderr, "Couldn't load texture: %s\n", path);
  177. return 0;
  178. }
  179. GLuint tex;
  180. glGenTextures(1, &tex);
  181. glBindTexture(GL_TEXTURE_2D, tex);
  182. #ifdef GLES
  183. glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height,
  184. 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
  185. #else
  186. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
  187. 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
  188. #endif
  189. free(data);
  190. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  191. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  192. return tex;
  193. }
  194. void retro_init(void)
  195. {}
  196. void retro_deinit(void)
  197. {}
  198. unsigned retro_api_version(void)
  199. {
  200. return RETRO_API_VERSION;
  201. }
  202. void retro_set_controller_port_device(unsigned port, unsigned device)
  203. {
  204. (void)port;
  205. (void)device;
  206. }
  207. void retro_get_system_info(struct retro_system_info *info)
  208. {
  209. memset(info, 0, sizeof(*info));
  210. info->library_name = "TestCore GL";
  211. info->library_version = "v1";
  212. info->need_fullpath = false;
  213. info->valid_extensions = "png";
  214. }
  215. void retro_get_system_av_info(struct retro_system_av_info *info)
  216. {
  217. info->timing.fps = 60.0;
  218. info->timing.sample_rate = 30000.0;
  219. info->geometry.base_width = 640;
  220. info->geometry.base_height = 480;
  221. info->geometry.max_width = 640;
  222. info->geometry.max_height = 480;
  223. }
  224. static retro_video_refresh_t video_cb;
  225. static retro_audio_sample_t audio_cb;
  226. static retro_audio_sample_batch_t audio_batch_cb;
  227. static retro_environment_t environ_cb;
  228. static retro_input_poll_t input_poll_cb;
  229. static retro_input_state_t input_state_cb;
  230. void retro_set_environment(retro_environment_t cb)
  231. {
  232. environ_cb = cb;
  233. }
  234. void retro_set_audio_sample(retro_audio_sample_t cb)
  235. {
  236. audio_cb = cb;
  237. }
  238. void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
  239. {
  240. audio_batch_cb = cb;
  241. }
  242. void retro_set_input_poll(retro_input_poll_t cb)
  243. {
  244. input_poll_cb = cb;
  245. }
  246. void retro_set_input_state(retro_input_state_t cb)
  247. {
  248. input_state_cb = cb;
  249. }
  250. void retro_set_video_refresh(retro_video_refresh_t cb)
  251. {
  252. video_cb = cb;
  253. }
  254. static vec3 check_input()
  255. {
  256. input_poll_cb();
  257. int x = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
  258. int y = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
  259. x = std::max(std::min(x, 20), -20);
  260. y = std::max(std::min(y, 20), -20);
  261. camera_rot_x -= 0.20 * x;
  262. camera_rot_y -= 0.10 * y;
  263. camera_rot_y = std::max(std::min(camera_rot_y, 80.0f), -80.0f);
  264. mat4 look_rot_x = rotate(mat4(1.0), camera_rot_x, vec3(0, 1, 0));
  265. mat4 look_rot_y = rotate(mat4(1.0), camera_rot_y, vec3(1, 0, 0));
  266. vec3 look_dir = vec3(look_rot_x * look_rot_y * vec4(0, 0, -1, 0));
  267. vec3 look_dir_side = vec3(look_rot_x * vec4(1, 0, 0, 0));
  268. mat3 s = mat3(scale(mat4(1.0), vec3(0.25, 0.25, 0.25)));
  269. if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP))
  270. player_pos += s * look_dir;
  271. if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN))
  272. player_pos -= s * look_dir;
  273. if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT))
  274. player_pos -= s * look_dir_side;
  275. if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT))
  276. player_pos += s * look_dir_side;
  277. return look_dir;
  278. }
  279. void retro_run(void)
  280. {
  281. vec3 look_dir = check_input();
  282. glBindFramebuffer(GL_FRAMEBUFFER, hw_render.get_current_framebuffer());
  283. glClearColor(0.1, 0.1, 0.1, 1.0);
  284. glViewport(0, 0, 640, 480);
  285. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  286. glUseProgram(prog);
  287. //glBindVertexArray(vao);
  288. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  289. int vloc = glGetAttribLocation(prog, "aVertex");
  290. glVertexAttribPointer(vloc, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, vert)));
  291. glEnableVertexAttribArray(vloc);
  292. int nloc = glGetAttribLocation(prog, "aNormal");
  293. glVertexAttribPointer(nloc, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, normal)));
  294. glEnableVertexAttribArray(nloc);
  295. int tcloc = glGetAttribLocation(prog, "aTexCoord");
  296. glVertexAttribPointer(tcloc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, tex)));
  297. glEnableVertexAttribArray(tcloc);
  298. glBindBuffer(GL_ARRAY_BUFFER, mbo);
  299. int mloc = glGetAttribLocation(prog, "aOffset");
  300. glVertexAttribPointer(mloc, 4, GL_FLOAT, GL_FALSE, 0, 0);
  301. glVertexAttribDivisor(mloc, 1); // Update per instance.
  302. glEnableVertexAttribArray(mloc);
  303. glEnable(GL_DEPTH_TEST);
  304. glEnable(GL_CULL_FACE);
  305. int tloc = glGetUniformLocation(prog, "uTexture");
  306. glUniform1i(tloc, 0);
  307. glActiveTexture(GL_TEXTURE0);
  308. glBindTexture(GL_TEXTURE_2D, tex);
  309. int lloc = glGetUniformLocation(prog, "light_pos");
  310. vec3 light_pos(0, 150, 15);
  311. glUniform3fv(lloc, 1, &light_pos[0]);
  312. vec4 ambient_light(0.2, 0.2, 0.2, 1.0);
  313. lloc = glGetUniformLocation(prog, "ambient_light");
  314. glUniform4fv(lloc, 1, &ambient_light[0]);
  315. int vploc = glGetUniformLocation(prog, "uVP");
  316. mat4 view = lookAt(player_pos, player_pos + look_dir, vec3(0, 1, 0));
  317. mat4 proj = scale(mat4(1.0), vec3(1, -1, 1)) * perspective(45.0f, 640.0f / 480.0f, 5.0f, 500.0f);
  318. mat4 vp = proj * view;
  319. glUniformMatrix4fv(vploc, 1, GL_FALSE, &vp[0][0]);
  320. int modelloc = glGetUniformLocation(prog, "uM");
  321. mat4 model = mat4(1.0);
  322. glUniformMatrix4fv(modelloc, 1, GL_FALSE, &model[0][0]);
  323. if (update)
  324. {
  325. update = false;
  326. glBindBuffer(GL_ARRAY_BUFFER, mbo);
  327. GLfloat *buf = (GLfloat*)glMapBufferRange(GL_ARRAY_BUFFER, 0,
  328. CUBE_SIZE * CUBE_SIZE * CUBE_SIZE * 4 * sizeof(GLfloat),
  329. GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
  330. for (unsigned x = 0; x < CUBE_SIZE; x++)
  331. for (unsigned y = 0; y < CUBE_SIZE; y++)
  332. for (unsigned z = 0; z < CUBE_SIZE; z++)
  333. {
  334. GLfloat *off = buf + 4 * ((CUBE_SIZE * CUBE_SIZE * z) + (CUBE_SIZE * y) + x);
  335. off[0] = 4.0f * ((float)x - CUBE_SIZE / 2);
  336. off[1] = 4.0f * ((float)y - CUBE_SIZE / 2);
  337. off[2] = -100.0f + 4.0f * ((float)z - CUBE_SIZE / 2);
  338. }
  339. glUnmapBuffer(GL_ARRAY_BUFFER);
  340. glBindBuffer(GL_ARRAY_BUFFER, 0);
  341. }
  342. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  343. glDrawElementsInstanced(GL_TRIANGLES, ARRAY_SIZE(indices),
  344. GL_UNSIGNED_BYTE, NULL, CUBE_SIZE * CUBE_SIZE * CUBE_SIZE);
  345. glUseProgram(0);
  346. //glBindVertexArray(0);
  347. glBindBuffer(GL_ARRAY_BUFFER, 0);
  348. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  349. glDisableVertexAttribArray(vloc);
  350. glDisableVertexAttribArray(nloc);
  351. glDisableVertexAttribArray(tcloc);
  352. glDisableVertexAttribArray(mloc);
  353. glBindTexture(GL_TEXTURE_2D, 0);
  354. video_cb(RETRO_HW_FRAME_BUFFER_VALID, 640, 480, 0);
  355. }
  356. static void context_reset(void)
  357. {
  358. fprintf(stderr, "Context reset!\n");
  359. #ifndef GLES
  360. glewExperimental = GL_TRUE;
  361. glewInit();
  362. #endif
  363. compile_program();
  364. setup_vao();
  365. tex = load_texture(texpath.c_str());
  366. }
  367. bool retro_load_game(const struct retro_game_info *info)
  368. {
  369. enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
  370. if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
  371. {
  372. fprintf(stderr, "XRGB8888 is not supported.\n");
  373. return false;
  374. }
  375. #ifdef GLES
  376. hw_render.context_type = RETRO_HW_CONTEXT_OPENGLES2;
  377. #else
  378. hw_render.context_type = RETRO_HW_CONTEXT_OPENGL;
  379. #endif
  380. hw_render.context_reset = context_reset;
  381. hw_render.depth = true;
  382. if (!environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render))
  383. return false;
  384. fprintf(stderr, "Loaded game!\n");
  385. player_pos = vec3(0, 0, 0);
  386. texpath = info->path;
  387. return true;
  388. }
  389. void retro_unload_game(void)
  390. {}
  391. unsigned retro_get_region(void)
  392. {
  393. return RETRO_REGION_NTSC;
  394. }
  395. bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num)
  396. {
  397. (void)type;
  398. (void)info;
  399. (void)num;
  400. return false;
  401. }
  402. size_t retro_serialize_size(void)
  403. {
  404. return 0;
  405. }
  406. bool retro_serialize(void *data, size_t size)
  407. {
  408. (void)data;
  409. (void)size;
  410. return false;
  411. }
  412. bool retro_unserialize(const void *data, size_t size)
  413. {
  414. (void)data;
  415. (void)size;
  416. return false;
  417. }
  418. void *retro_get_memory_data(unsigned id)
  419. {
  420. (void)id;
  421. return NULL;
  422. }
  423. size_t retro_get_memory_size(unsigned id)
  424. {
  425. (void)id;
  426. return 0;
  427. }
  428. void retro_reset(void)
  429. {}
  430. void retro_cheat_reset(void)
  431. {}
  432. void retro_cheat_set(unsigned index, bool enabled, const char *code)
  433. {
  434. (void)index;
  435. (void)enabled;
  436. (void)code;
  437. }