Mercurial > repos > blastem
comparison render_sdl.c @ 1184:b1147418254a
Overscan is now configurable
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 18 Jan 2017 23:43:36 -0800 |
parents | e758ddbf0624 |
children | 6a4503fad67e |
comparison
equal
deleted
inserted
replaced
1183:8d8c71ebbbce | 1184:b1147418254a |
---|---|
131 { | 131 { |
132 return 255 << 24 | r << 16 | g << 8 | b; | 132 return 255 << 24 | r << 16 | g << 8 | b; |
133 } | 133 } |
134 | 134 |
135 #ifndef DISABLE_OPENGL | 135 #ifndef DISABLE_OPENGL |
136 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, at_pos; | 136 static GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, un_height, at_pos; |
137 | 137 |
138 static GLfloat vertex_data[] = { | 138 static GLfloat vertex_data[] = { |
139 -1.0f, -1.0f, | 139 -1.0f, -1.0f, |
140 1.0f, -1.0f, | 140 1.0f, -1.0f, |
141 -1.0f, 1.0f, | 141 -1.0f, 1.0f, |
209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 209 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
212 if (i < 2) { | 212 if (i < 2) { |
213 //TODO: Fixme for PAL + invalid display mode | 213 //TODO: Fixme for PAL + invalid display mode |
214 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); | 214 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); |
215 } else { | 215 } else { |
216 uint32_t blank = 255 << 24; | 216 uint32_t blank = 255 << 24; |
217 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); | 217 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); |
218 } | 218 } |
219 } | 219 } |
237 exit(1); | 237 exit(1); |
238 } | 238 } |
239 un_textures[0] = glGetUniformLocation(program, "textures[0]"); | 239 un_textures[0] = glGetUniformLocation(program, "textures[0]"); |
240 un_textures[1] = glGetUniformLocation(program, "textures[1]"); | 240 un_textures[1] = glGetUniformLocation(program, "textures[1]"); |
241 un_width = glGetUniformLocation(program, "width"); | 241 un_width = glGetUniformLocation(program, "width"); |
242 un_height = glGetUniformLocation(program, "height"); | |
242 at_pos = glGetAttribLocation(program, "pos"); | 243 at_pos = glGetAttribLocation(program, "pos"); |
243 } else { | 244 } else { |
244 #endif | 245 #endif |
245 | 246 |
246 //TODO: Fixme for PAL + invalid display mode | 247 //TODO: Fixme for invalid display mode |
247 sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); | 248 sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 588); |
248 #ifndef DISABLE_OPENGL | 249 #ifndef DISABLE_OPENGL |
249 } | 250 } |
250 #endif | 251 #endif |
251 } | 252 } |
252 | 253 |
262 SDL_DestroyTexture(sdl_textures[i]); | 263 SDL_DestroyTexture(sdl_textures[i]); |
263 } | 264 } |
264 } | 265 } |
265 } | 266 } |
266 | 267 |
268 static uint32_t overscan_top[NUM_VID_STD] = {2, 21}; | |
269 static uint32_t overscan_bot[NUM_VID_STD] = {1, 17}; | |
270 static vid_std video_standard = VID_NTSC; | |
271 static char *vid_std_names[NUM_VID_STD] = {"ntsc", "pal"}; | |
267 void render_init(int width, int height, char * title, uint8_t fullscreen) | 272 void render_init(int width, int height, char * title, uint8_t fullscreen) |
268 { | 273 { |
269 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { | 274 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { |
270 fatal_error("Unable to init SDL: %s\n", SDL_GetError()); | 275 fatal_error("Unable to init SDL: %s\n", SDL_GetError()); |
271 } | 276 } |
289 is_fullscreen = fullscreen; | 294 is_fullscreen = fullscreen; |
290 | 295 |
291 render_gl = 0; | 296 render_gl = 0; |
292 tern_val def = {.ptrval = "off"}; | 297 tern_val def = {.ptrval = "off"}; |
293 char *vsync = tern_find_path_default(config, "video\0vsync\0", def).ptrval; | 298 char *vsync = tern_find_path_default(config, "video\0vsync\0", def).ptrval; |
299 | |
300 tern_val video_node = {.ptrval = NULL}; | |
301 tern_find(config, "video", &video_node); | |
302 tern_node *video = tern_get_node(video_node); | |
303 if (video) | |
304 { | |
305 for (int i = 0; i < NUM_VID_STD; i++) | |
306 { | |
307 video_node.ptrval = NULL; | |
308 tern_find(video, vid_std_names[i], &video_node); | |
309 tern_node *std_settings = tern_get_node(video_node); | |
310 if (std_settings) { | |
311 char *val = tern_find_path_default(std_settings, "overscan\0top\0", (tern_val){.ptrval = NULL}).ptrval; | |
312 if (val) { | |
313 overscan_top[i] = atoi(val); | |
314 } | |
315 val = tern_find_path_default(std_settings, "overscan\0bottom\0", (tern_val){.ptrval = NULL}).ptrval; | |
316 if (val) { | |
317 overscan_bot[i] = atoi(val); | |
318 } | |
319 } | |
320 } | |
321 } | |
294 | 322 |
295 #ifndef DISABLE_OPENGL | 323 #ifndef DISABLE_OPENGL |
296 flags |= SDL_WINDOW_OPENGL; | 324 flags |= SDL_WINDOW_OPENGL; |
297 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); | 325 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); |
298 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); | 326 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); |
416 SDL_JoystickEventState(SDL_ENABLE); | 444 SDL_JoystickEventState(SDL_ENABLE); |
417 | 445 |
418 atexit(render_quit); | 446 atexit(render_quit); |
419 } | 447 } |
420 | 448 |
449 void render_set_video_standard(vid_std std) | |
450 { | |
451 video_standard = std; | |
452 } | |
453 | |
421 void render_update_caption(char *title) | 454 void render_update_caption(char *title) |
422 { | 455 { |
423 caption = title; | 456 caption = title; |
424 free(fps_caption); | 457 free(fps_caption); |
425 fps_caption = NULL; | 458 fps_caption = NULL; |
470 #endif | 503 #endif |
471 | 504 |
472 void render_framebuffer_updated(uint8_t which, int width) | 505 void render_framebuffer_updated(uint8_t which, int width) |
473 { | 506 { |
474 static uint8_t last; | 507 static uint8_t last; |
508 uint32_t height = which <= FRAMEBUFFER_EVEN | |
509 ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard]) | |
510 : 240; | |
475 #ifndef DISABLE_OPENGL | 511 #ifndef DISABLE_OPENGL |
476 if (render_gl && which <= FRAMEBUFFER_EVEN) { | 512 if (render_gl && which <= FRAMEBUFFER_EVEN) { |
477 glBindTexture(GL_TEXTURE_2D, textures[which]); | 513 glBindTexture(GL_TEXTURE_2D, textures[which]); |
478 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); | 514 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, height, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf + 320 * overscan_top[video_standard]); |
479 | 515 |
480 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | 516 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
481 glClear(GL_COLOR_BUFFER_BIT); | 517 glClear(GL_COLOR_BUFFER_BIT); |
482 | 518 |
483 glUseProgram(program); | 519 glUseProgram(program); |
488 glActiveTexture(GL_TEXTURE1); | 524 glActiveTexture(GL_TEXTURE1); |
489 glBindTexture(GL_TEXTURE_2D, textures[last != which ? 1 : scanlines ? 2 : 0]); | 525 glBindTexture(GL_TEXTURE_2D, textures[last != which ? 1 : scanlines ? 2 : 0]); |
490 glUniform1i(un_textures[1], 1); | 526 glUniform1i(un_textures[1], 1); |
491 | 527 |
492 glUniform1f(un_width, width); | 528 glUniform1f(un_width, width); |
529 glUniform1f(un_height, height); | |
493 | 530 |
494 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); | 531 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); |
495 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); | 532 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); |
496 glEnableVertexAttribArray(at_pos); | 533 glEnableVertexAttribArray(at_pos); |
497 | 534 |
501 glDisableVertexAttribArray(at_pos); | 538 glDisableVertexAttribArray(at_pos); |
502 | 539 |
503 SDL_GL_SwapWindow(main_window); | 540 SDL_GL_SwapWindow(main_window); |
504 } else { | 541 } else { |
505 #endif | 542 #endif |
506 uint32_t height = 240; | |
507 if (which <= FRAMEBUFFER_EVEN && last != which) { | 543 if (which <= FRAMEBUFFER_EVEN && last != which) { |
508 uint8_t *cur_dst = (uint8_t *)locked_pixels; | 544 uint8_t *cur_dst = (uint8_t *)locked_pixels; |
509 uint8_t *cur_saved = (uint8_t *)texture_buf; | 545 uint8_t *cur_saved = (uint8_t *)texture_buf; |
510 uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch; | 546 uint32_t dst_off = which == FRAMEBUFFER_EVEN ? 0 : locked_pitch; |
511 uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0; | 547 uint32_t src_off = which == FRAMEBUFFER_EVEN ? locked_pitch : 0; |
512 for (int i = 0; i < 240; ++i) | 548 for (int i = 0; i < height; ++i) |
513 { | 549 { |
514 //copy saved line from other field | 550 //copy saved line from other field |
515 memcpy(cur_dst + dst_off, cur_saved, locked_pitch); | 551 memcpy(cur_dst + dst_off, cur_saved, locked_pitch); |
516 //save line from this field to buffer for next frame | 552 //save line from this field to buffer for next frame |
517 memcpy(cur_saved, cur_dst + src_off, locked_pitch); | 553 memcpy(cur_saved, cur_dst + src_off, locked_pitch); |
521 height = 480; | 557 height = 480; |
522 } | 558 } |
523 SDL_UnlockTexture(sdl_textures[which]); | 559 SDL_UnlockTexture(sdl_textures[which]); |
524 SDL_Rect src_clip = { | 560 SDL_Rect src_clip = { |
525 .x = 0, | 561 .x = 0, |
526 .y = 0, | 562 .y = overscan_top[video_standard], |
527 .w = width, | 563 .w = width, |
528 .h = height | 564 .h = height |
529 }; | 565 }; |
530 SDL_RenderCopy(main_renderer, sdl_textures[which], &src_clip, &main_clip); | 566 SDL_RenderCopy(main_renderer, sdl_textures[which], &src_clip, &main_clip); |
531 SDL_RenderPresent(main_renderer); | 567 SDL_RenderPresent(main_renderer); |