render_yuv.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /* MegaZeux
  2. *
  3. * Copyright (C) 2007 Alan Williams <mralert@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include <stdlib.h>
  20. #include "platform.h"
  21. #include "graphics.h"
  22. #include "render.h"
  23. #include "render_layer.h"
  24. #include "render_sdl.h"
  25. #include "renderers.h"
  26. #include "util.h"
  27. #include "yuv.h"
  28. #if SDL_VERSION_ATLEAST(2,0,0)
  29. #error Overlay renderer no longer supported for SDL 2+. Use softscale!
  30. #endif
  31. #define YUV1_OVERLAY_WIDTH (SCREEN_PIX_W * 2)
  32. #define YUV1_OVERLAY_HEIGHT SCREEN_PIX_H
  33. #define YUV2_OVERLAY_WIDTH SCREEN_PIX_W
  34. #define YUV2_OVERLAY_HEIGHT SCREEN_PIX_H
  35. struct yuv_render_data
  36. {
  37. struct sdl_render_data sdl;
  38. void (*set_colors_mzx)(struct graphics_data *, Uint32 *, Uint8, Uint8);
  39. Uint32 (*rgb_to_yuv)(Uint8 r, Uint8 g, Uint8 b);
  40. Uint32 bpp;
  41. Uint32 w;
  42. Uint32 h;
  43. };
  44. static boolean yuv_set_video_mode_size(struct graphics_data *graphics,
  45. int width, int height, int depth, boolean fullscreen, boolean resize,
  46. int yuv_width, int yuv_height)
  47. {
  48. struct yuv_render_data *render_data = graphics->render_data;
  49. // the YUV renderer _requires_ 32bit colour
  50. render_data->sdl.screen = SDL_SetVideoMode(width, height, 32,
  51. sdl_flags(depth, fullscreen, false, resize) | SDL_ANYFORMAT);
  52. if(!render_data->sdl.screen)
  53. goto err_free;
  54. // try with a YUY2 pixel format first
  55. render_data->rgb_to_yuv = rgb_to_yuy2;
  56. render_data->set_colors_mzx = yuy2_subsample_set_colors_mzx;
  57. render_data->sdl.overlay = SDL_CreateYUVOverlay(yuv_width, yuv_height,
  58. SDL_YUY2_OVERLAY, render_data->sdl.screen);
  59. // didn't work, try with a UYVY pixel format next
  60. if(!render_data->sdl.overlay)
  61. {
  62. render_data->rgb_to_yuv = rgb_to_uyvy;
  63. render_data->set_colors_mzx = uyvy_subsample_set_colors_mzx;
  64. render_data->sdl.overlay = SDL_CreateYUVOverlay(yuv_width, yuv_height,
  65. SDL_UYVY_OVERLAY, render_data->sdl.screen);
  66. }
  67. // Since we support this format now too, might as well try.
  68. if(!render_data->sdl.overlay)
  69. {
  70. render_data->rgb_to_yuv = rgb_to_yvyu;
  71. render_data->set_colors_mzx = yvyu_subsample_set_colors_mzx;
  72. render_data->sdl.overlay = SDL_CreateYUVOverlay(yuv_width, yuv_height,
  73. SDL_YVYU_OVERLAY, render_data->sdl.screen);
  74. }
  75. // failed to create an overlay
  76. if(!render_data->sdl.overlay)
  77. goto err_free;
  78. render_data->w = width;
  79. render_data->h = height;
  80. return true;
  81. err_free:
  82. sdl_destruct_window(graphics);
  83. return false;
  84. }
  85. static boolean yuv1_set_video_mode(struct graphics_data *graphics,
  86. int width, int height, int depth, boolean fullscreen, boolean resize)
  87. {
  88. struct yuv_render_data *render_data = graphics->render_data;
  89. render_data->bpp = 32;
  90. return yuv_set_video_mode_size(graphics, width, height, depth, fullscreen,
  91. resize, YUV1_OVERLAY_WIDTH, YUV1_OVERLAY_HEIGHT);
  92. }
  93. static boolean yuv2_set_video_mode(struct graphics_data *graphics,
  94. int width, int height, int depth, boolean fullscreen, boolean resize)
  95. {
  96. struct yuv_render_data *render_data = graphics->render_data;
  97. render_data->bpp = 16;
  98. return yuv_set_video_mode_size(graphics, width, height, depth, fullscreen,
  99. resize, YUV2_OVERLAY_WIDTH, YUV2_OVERLAY_HEIGHT);
  100. }
  101. static boolean yuv_init_video(struct graphics_data *graphics,
  102. struct config_info *conf)
  103. {
  104. struct yuv_render_data *render_data = cmalloc(sizeof(struct yuv_render_data));
  105. if(!render_data)
  106. return false;
  107. memset(render_data, 0, sizeof(struct yuv_render_data));
  108. graphics->render_data = render_data;
  109. graphics->allow_resize = conf->allow_resize;
  110. graphics->ratio = conf->video_ratio;
  111. if(!set_video_mode())
  112. {
  113. free(render_data);
  114. graphics->render_data = NULL;
  115. return false;
  116. }
  117. return true;
  118. }
  119. static void yuv_free_video(struct graphics_data *graphics)
  120. {
  121. sdl_destruct_window(graphics);
  122. free(graphics->render_data);
  123. graphics->render_data = NULL;
  124. }
  125. static boolean yuv_check_video_mode(struct graphics_data *graphics,
  126. int width, int height, int depth, boolean fullscreen, boolean resize)
  127. {
  128. return SDL_VideoModeOK(width, height, 32,
  129. sdl_flags(depth, fullscreen, false, resize) | SDL_ANYFORMAT);
  130. }
  131. static void yuv_update_colors(struct graphics_data *graphics,
  132. struct rgb_color *palette, Uint32 count)
  133. {
  134. struct yuv_render_data *render_data = graphics->render_data;
  135. Uint32 i;
  136. for(i = 0; i < count; i++)
  137. {
  138. graphics->flat_intensity_palette[i] =
  139. render_data->rgb_to_yuv(palette[i].r, palette[i].g, palette[i].b);
  140. }
  141. }
  142. static void yuv_lock_overlay(struct yuv_render_data *render_data,
  143. Uint32 **pixels, Uint32 *pitch)
  144. {
  145. SDL_LockYUVOverlay(render_data->sdl.overlay);
  146. *pixels = (Uint32 *)render_data->sdl.overlay->pixels[0];
  147. *pitch = render_data->sdl.overlay->pitches[0];
  148. }
  149. static void yuv_unlock_overlay(struct yuv_render_data *render_data)
  150. {
  151. SDL_UnlockYUVOverlay(render_data->sdl.overlay);
  152. }
  153. static void yuv_render_graph(struct graphics_data *graphics)
  154. {
  155. struct yuv_render_data *render_data = graphics->render_data;
  156. Uint32 mode = graphics->screen_mode;
  157. Uint32 bpp = render_data->bpp;
  158. Uint32 *pixels;
  159. Uint32 pitch;
  160. yuv_lock_overlay(render_data, &pixels, &pitch);
  161. if(bpp == 16)
  162. {
  163. // Subsampled mode
  164. if(!mode)
  165. render_graph16((Uint16 *)pixels, pitch, graphics,
  166. render_data->set_colors_mzx);
  167. else
  168. render_graph16((Uint16 *)pixels, pitch, graphics, set_colors32[mode]);
  169. }
  170. else
  171. {
  172. if(!mode)
  173. render_graph32(pixels, pitch, graphics, set_colors32[mode]);
  174. else
  175. render_graph32s(pixels, pitch, graphics, set_colors32[mode]);
  176. }
  177. yuv_unlock_overlay(render_data);
  178. }
  179. static void yuv1_render_layer(struct graphics_data *graphics,
  180. struct video_layer *layer)
  181. {
  182. struct yuv_render_data *render_data = graphics->render_data;
  183. Uint32 bpp = render_data->bpp;
  184. Uint32 *pixels;
  185. Uint32 pitch;
  186. yuv_lock_overlay(render_data, &pixels, &pitch);
  187. render_layer(pixels, bpp, pitch, graphics, layer);
  188. yuv_unlock_overlay(render_data);
  189. }
  190. static void yuv_render_cursor(struct graphics_data *graphics,
  191. Uint32 x, Uint32 y, Uint16 color, Uint8 lines, Uint8 offset)
  192. {
  193. struct yuv_render_data *render_data = graphics->render_data;
  194. Uint32 bpp = render_data->bpp;
  195. Uint32 *pixels;
  196. Uint32 pitch;
  197. yuv_lock_overlay(render_data, &pixels, &pitch);
  198. render_cursor(pixels, pitch, bpp, x, y,
  199. graphics->flat_intensity_palette[color], lines, offset);
  200. yuv_unlock_overlay(render_data);
  201. }
  202. static void yuv_render_mouse(struct graphics_data *graphics,
  203. Uint32 x, Uint32 y, Uint8 w, Uint8 h)
  204. {
  205. struct yuv_render_data *render_data = graphics->render_data;
  206. Uint32 bpp = render_data->bpp;
  207. Uint32 *pixels;
  208. Uint32 pitch;
  209. yuv_lock_overlay(render_data, &pixels, &pitch);
  210. render_mouse(pixels, pitch, bpp, x, y, 0xFFFFFFFF, 0x0, w, h);
  211. yuv_unlock_overlay(render_data);
  212. }
  213. static void yuv_sync_screen(struct graphics_data *graphics)
  214. {
  215. struct yuv_render_data *render_data = graphics->render_data;
  216. int width = render_data->w, v_width;
  217. int height = render_data->h, v_height;
  218. SDL_Rect rect;
  219. // FIXME: Putting this here is suboptimal
  220. fix_viewport_ratio(width, height, &v_width, &v_height, graphics->ratio);
  221. rect.x = (width - v_width) >> 1;
  222. rect.y = (height - v_height) >> 1;
  223. rect.w = v_width;
  224. rect.h = v_height;
  225. SDL_DisplayYUVOverlay(render_data->sdl.overlay, &rect);
  226. }
  227. void render_yuv1_register(struct renderer *renderer)
  228. {
  229. memset(renderer, 0, sizeof(struct renderer));
  230. renderer->init_video = yuv_init_video;
  231. renderer->free_video = yuv_free_video;
  232. renderer->check_video_mode = yuv_check_video_mode;
  233. renderer->set_video_mode = yuv1_set_video_mode;
  234. renderer->update_colors = yuv_update_colors;
  235. renderer->resize_screen = resize_screen_standard;
  236. renderer->get_screen_coords = get_screen_coords_scaled;
  237. renderer->set_screen_coords = set_screen_coords_scaled;
  238. renderer->render_graph = yuv_render_graph;
  239. renderer->render_layer = yuv1_render_layer;
  240. renderer->render_cursor = yuv_render_cursor;
  241. renderer->render_mouse = yuv_render_mouse;
  242. renderer->sync_screen = yuv_sync_screen;
  243. }
  244. void render_yuv2_register(struct renderer *renderer)
  245. {
  246. render_yuv1_register(renderer);
  247. renderer->set_video_mode = yuv2_set_video_mode;
  248. renderer->render_layer = NULL;
  249. }