render_path.ts 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. type render_target_t = {
  2. name?: string;
  3. width?: i32;
  4. height?: i32;
  5. // Opt
  6. format?: string;
  7. scale?: f32;
  8. // Runtime
  9. _image?: gpu_texture_t;
  10. };
  11. type cached_shader_context_t = {
  12. context?: shader_context_t;
  13. };
  14. enum draw_order_t {
  15. DIST, // Early-z
  16. SHADER, // Less state changes
  17. }
  18. let render_path_commands: ()=>void = null;
  19. let render_path_render_targets: map_t<string, render_target_t> = map_create();
  20. let render_path_current_w: i32;
  21. let render_path_current_h: i32;
  22. let _render_path_frame_time: f32 = 0.0;
  23. let _render_path_frame: i32 = 0;
  24. let _render_path_current_target: render_target_t = null;
  25. let _render_path_current_image: gpu_texture_t = null;
  26. let _render_path_draw_order: draw_order_t = draw_order_t.DIST;
  27. let _render_path_paused: bool = false;
  28. let _render_path_last_w: i32 = 0;
  29. let _render_path_last_h: i32 = 0;
  30. let _render_path_bind_params: string[];
  31. let _render_path_meshes_sorted: bool;
  32. let _render_path_last_frame_time: f32 = 0.0;
  33. let _render_path_loading: i32 = 0;
  34. let _render_path_cached_shader_contexts: map_t<string, cached_shader_context_t> = map_create();
  35. function render_path_ready(): bool {
  36. return _render_path_loading == 0;
  37. }
  38. function render_path_render_frame() {
  39. if (!render_path_ready() || _render_path_paused) {
  40. return;
  41. }
  42. if (_render_path_last_w > 0 && (_render_path_last_w != sys_w() || _render_path_last_h != sys_h())) {
  43. render_path_resize();
  44. }
  45. _render_path_last_w = sys_w();
  46. _render_path_last_h = sys_h();
  47. _render_path_frame_time = sys_time() -_render_path_last_frame_time;
  48. _render_path_last_frame_time = sys_time();
  49. render_path_current_w = sys_w();
  50. render_path_current_h = sys_h();
  51. _render_path_meshes_sorted = false;
  52. render_path_commands();
  53. _render_path_frame++;
  54. }
  55. function render_path_set_target(target: string, additional: string[] = null, depth_buffer: string = null, flags: i32 = clear_flag_t.NONE, color: i32 = 0, depth: f32 = 0.0) {
  56. if (_render_path_current_image != null) {
  57. render_path_end();
  58. }
  59. if (target == "") { // Framebuffer
  60. _render_path_current_target = null;
  61. render_path_current_w = sys_w();
  62. render_path_current_h = sys_h();
  63. _gpu_begin(null, null, null, flags, color, depth);
  64. gpu_viewport(sys_x(), render_path_current_h - (sys_h() - sys_y()), sys_w(), sys_h());
  65. }
  66. else { // Render target
  67. let rt: render_target_t = map_get(render_path_render_targets, target);
  68. _render_path_current_target = rt;
  69. let additional_images: gpu_texture_t[] = null;
  70. if (additional != null) {
  71. additional_images = [];
  72. for (let i: i32 = 0; i < additional.length; ++i) {
  73. let s: string = additional[i];
  74. let t: render_target_t = map_get(render_path_render_targets, s);
  75. array_push(additional_images, t._image);
  76. }
  77. }
  78. render_path_current_w = rt._image.width;
  79. render_path_current_h = rt._image.height;
  80. let db: render_target_t = map_get(render_path_render_targets, depth_buffer);
  81. _render_path_current_image = rt._image;
  82. _gpu_begin(rt._image, additional_images, db != null ? db._image : null, flags, color, depth);
  83. }
  84. _render_path_bind_params = null;
  85. }
  86. function render_path_end() {
  87. gpu_end();
  88. _render_path_current_image = null;
  89. _render_path_bind_params = null;
  90. }
  91. function _render_path_sort_dist(a: any_ptr, b: any_ptr): i32 {
  92. let ma: mesh_object_t = DEREFERENCE(a);
  93. let mb: mesh_object_t = DEREFERENCE(b);
  94. return ma.camera_dist >= mb.camera_dist ? 1 : -1;
  95. }
  96. function render_path_sort_meshes_dist(meshes: mesh_object_t[]) {
  97. array_sort(meshes, _render_path_sort_dist);
  98. }
  99. function _render_path_sort_shader(a: any_ptr, b: any_ptr): i32 {
  100. let ma: mesh_object_t = DEREFERENCE(a);
  101. let mb: mesh_object_t = DEREFERENCE(b);
  102. return strcmp(ma.materials[0].name, mb.materials[0].name);
  103. }
  104. function render_path_sort_meshes_shader(meshes: mesh_object_t[]) {
  105. array_sort(meshes, _render_path_sort_shader);
  106. }
  107. function render_path_draw_meshes(context: string) {
  108. render_path_submit_draw(context);
  109. render_path_end();
  110. }
  111. function render_path_submit_draw(context: string) {
  112. let camera: camera_object_t = scene_camera;
  113. let meshes: mesh_object_t[] = scene_meshes;
  114. _mesh_object_last_pipeline = null;
  115. if (!_render_path_meshes_sorted && camera != null) { // Order max once per frame for now
  116. let cam_x: f32 = transform_world_x(camera.base.transform);
  117. let cam_y: f32 = transform_world_y(camera.base.transform);
  118. let cam_z: f32 = transform_world_z(camera.base.transform);
  119. for (let i: i32 = 0; i < meshes.length; ++i) {
  120. let mesh: mesh_object_t = meshes[i];
  121. mesh_object_compute_camera_dist(mesh, cam_x, cam_y, cam_z);
  122. }
  123. if (_render_path_draw_order == draw_order_t.SHADER) {
  124. render_path_sort_meshes_shader(meshes);
  125. }
  126. else {
  127. render_path_sort_meshes_dist(meshes);
  128. }
  129. _render_path_meshes_sorted = true;
  130. }
  131. for (let i: i32 = 0; i < meshes.length; ++i) {
  132. let mesh: mesh_object_t = meshes[i];
  133. mesh_object_render(mesh, context, _render_path_bind_params);
  134. }
  135. }
  136. function render_path_draw_skydome(handle: string) {
  137. if (const_data_skydome_vb == null) {
  138. const_data_create_skydome_data();
  139. }
  140. let cc: cached_shader_context_t = map_get(_render_path_cached_shader_contexts, handle);
  141. if (cc.context == null) {
  142. return; // World data not specified
  143. }
  144. gpu_set_pipeline(cc.context._.pipe);
  145. uniforms_set_context_consts(cc.context, _render_path_bind_params);
  146. uniforms_set_obj_consts(cc.context, null); // External hosek
  147. gpu_set_vertex_buffer(const_data_skydome_vb);
  148. gpu_set_index_buffer(const_data_skydome_ib);
  149. gpu_draw();
  150. render_path_end();
  151. }
  152. function render_path_bind_target(target: string, uniform: string) {
  153. if (_render_path_bind_params != null) {
  154. array_push(_render_path_bind_params, target);
  155. array_push(_render_path_bind_params, uniform);
  156. }
  157. else {
  158. _render_path_bind_params = [target, uniform];
  159. }
  160. }
  161. // Full-screen triangle
  162. function render_path_draw_shader(handle: string) {
  163. // file/data_name/context
  164. let cc: cached_shader_context_t = map_get(_render_path_cached_shader_contexts, handle);
  165. if (const_data_screen_aligned_vb == null) {
  166. const_data_create_screen_aligned_data();
  167. }
  168. gpu_set_pipeline(cc.context._.pipe);
  169. uniforms_set_context_consts(cc.context, _render_path_bind_params);
  170. uniforms_set_obj_consts(cc.context, null);
  171. gpu_set_vertex_buffer(const_data_screen_aligned_vb);
  172. gpu_set_index_buffer(const_data_screen_aligned_ib);
  173. gpu_draw();
  174. render_path_end();
  175. }
  176. function render_path_load_shader(handle: string) {
  177. _render_path_loading++;
  178. let cc: cached_shader_context_t = map_get(_render_path_cached_shader_contexts, handle);
  179. if (cc != null) {
  180. _render_path_loading--;
  181. return;
  182. }
  183. cc = {};
  184. map_set(_render_path_cached_shader_contexts, handle, cc);
  185. // file/data_name/context
  186. let shader_path: string[] = string_split(handle, "/");
  187. let res: shader_data_t = data_get_shader(shader_path[0], shader_path[1]);
  188. cc.context = shader_data_get_context(res, shader_path[2]);
  189. _render_path_loading--;
  190. }
  191. function render_path_unload_shader(handle: string) {
  192. map_delete(_render_path_cached_shader_contexts, handle);
  193. // file/data_name/context
  194. let shader_path: string[] = string_split(handle, "/");
  195. // Todo: Handle context overrides (see data_get_shader())
  196. map_delete(data_cached_shaders, shader_path[1]);
  197. }
  198. function render_path_unload() {
  199. let render_targets_keys: string[] = map_keys(render_path_render_targets);
  200. for (let i: i32 = 0; i < render_targets_keys.length; ++i) {
  201. let rt: render_target_t = map_get(render_path_render_targets, render_targets_keys[i]);
  202. render_target_unload(rt);
  203. }
  204. }
  205. function render_path_resize() {
  206. if (iron_window_width() == 0 || iron_window_height() == 0) {
  207. return;
  208. }
  209. let render_targets_keys: string[] = map_keys(render_path_render_targets);
  210. for (let i: i32 = 0; i < render_targets_keys.length; ++i) {
  211. let rt: render_target_t = map_get(render_path_render_targets, render_targets_keys[i]);
  212. if (rt != null && rt.width == 0) {
  213. iron_delete_texture(rt._image);
  214. rt._image = render_path_create_image(rt);
  215. }
  216. }
  217. }
  218. function render_path_create_render_target(t: render_target_t): render_target_t {
  219. t._image = render_path_create_image(t);
  220. map_set(render_path_render_targets, t.name, t);
  221. return t;
  222. }
  223. function render_path_create_image(t: render_target_t): gpu_texture_t {
  224. let width: i32 = t.width == 0 ? sys_w() : t.width;
  225. let height: i32 = t.height == 0 ? sys_h() : t.height;
  226. width = math_floor(width * t.scale);
  227. height = math_floor(height * t.scale);
  228. if (width < 1) {
  229. width = 1;
  230. }
  231. if (height < 1) {
  232. height = 1;
  233. }
  234. return gpu_create_render_target(width, height,
  235. t.format != null ? render_path_get_tex_format(t.format) : tex_format_t.RGBA32);
  236. }
  237. function render_path_get_tex_format(s: string): tex_format_t {
  238. if (s == "RGBA32") {
  239. return tex_format_t.RGBA32;
  240. }
  241. if (s == "RGBA64") {
  242. return tex_format_t.RGBA64;
  243. }
  244. if (s == "RGBA128") {
  245. return tex_format_t.RGBA128;
  246. }
  247. if (s == "R32") {
  248. return tex_format_t.R32;
  249. }
  250. if (s == "R16") {
  251. return tex_format_t.R16;
  252. }
  253. if (s == "R8") {
  254. return tex_format_t.R8;
  255. }
  256. if (s == "D32") {
  257. return tex_format_t.D32;
  258. }
  259. return tex_format_t.RGBA32;
  260. }
  261. function render_target_create(): render_target_t {
  262. let raw: render_target_t = {};
  263. raw.scale = 1.0;
  264. return raw;
  265. }
  266. function render_target_unload(raw: render_target_t) {
  267. if (raw._image != null) {
  268. iron_delete_texture(raw._image);
  269. }
  270. }