/*
* src/sysvid.c
*
* Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). All rights reserved.
*
* The use and distribution terms for this software are contained in the file
* named README, which can be found in the root of this distribution. By
* using this software in any fashion, you are agreeing to be bound by the
* terms of this license.
*
* You must not remove this notice, or any other, from this software.
*/
#include <stdlib.h> // malloc
#include <string.h> // memset
#include <stdbool.h> // bool
#include <SDL2/SDL.h>
#include "system.h"
#include "game.h"
#include "img.h"
#define SCALE_FACTOR 4
U8 sysvid_fb[320 * 200]; // the framebuffer for this game is really 320x200
U8 want_fullscreen = FALSE;// TRUE;
U8 want_filter = TRUE;
U8 recreate_screen = FALSE;
static SDL_Window *window;
static SDL_Renderer *renderer;
static SDL_Texture *screen_texture;
// XBRZ scaler
void xbrz_scale (size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, bool has_alpha_channel);
void nearest_neighbor_scale (const uint32_t *src, int srcWidth, int srcHeight, uint32_t *trg, int trgWidth, int trgHeight);
// Initialise video
void sysvid_init (void)
{
// SDL init
if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
sys_panic ("Fatal error: could not initialize SDL.\n");
// create game window
window = SDL_CreateWindow ("Rick Dangerous",
SDL_WINDOWPOS_UNDEFINED, // x
SDL_WINDOWPOS_UNDEFINED, // y
(want_fullscreen ? 0 : 1024), // let system assign width in fullscreen mode
(want_fullscreen ? 0 : 768), // let system assign height in fullscreen mode
(want_fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0));
if (window == NULL)
sys_panic ("Fatal error: SDL can not create game window.\n");
// create renderer
renderer = SDL_CreateRenderer (window, -1, 0);
if (renderer == NULL)
sys_panic ("Fatal error: SDL can not create renderer\n");
// amke the scaled rendering look smoother
SDL_RenderSetLogicalSize (renderer, 320 * SCALE_FACTOR, 200 * SCALE_FACTOR);
// create a texture that will cover the whole window
screen_texture = SDL_CreateTexture (renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320 * SCALE_FACTOR, 200 * SCALE_FACTOR);
if (screen_texture == NULL)
sys_panic ("Fatal error: SDL can not create rendering surface\n");
// clear the screen to black
sysvid_clear ();
}
// Shutdown video
void sysvid_shutdown (void)
{
// SDL quit
SDL_Quit ();
}
// Clear screen
void sysvid_clear (void)
{
SDL_SetRenderDrawColor (renderer, 0, 0, 0, 255);
SDL_RenderClear (renderer);
SDL_RenderPresent (renderer);
memset (sysvid_fb
, 0, sizeof (sysvid_fb
));
}
// Update screen
void sysvid_paint (rect_t *rects)
{
static uint8_t screen_pixels[320 * 200 * 4];
static uint8_t upscaled_pixels[320 * SCALE_FACTOR * 200 * SCALE_FACTOR * 4];
static rect_t rect_whole = {0, 0, 320, 200, NULL}; // framebuffer coordinates. The framebuffer is 320x200.
static U8 palette[16][3] =
{
{0x00, 0x00, 0x00},
{0xd8, 0x00, 0x00},
{0xb0, 0x6c, 0x68},
{0xf8, 0x90, 0x68},
{0x20, 0x24, 0x20},
{0x00, 0x48, 0xb0},
{0x00, 0x6c, 0xd8},
{0x20, 0x48, 0x00},
{0x48, 0x6c, 0x20},
{0x48, 0x24, 0x00},
{0x90, 0x48, 0x00},
{0xd8, 0x6c, 0x00},
{0x48, 0x48, 0x48},
{0x68, 0x6c, 0x68},
{0x90, 0x90, 0x90},
{0xb0, 0xb4, 0xb0}
};
U16 x, y;
U8 *p, *q, *p0, *q0;
if (rects == NULL)
return;
if (recreate_screen)
{
recreate_screen = FALSE;
SDL_SetWindowFullscreen (window, (want_fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0));
sysvid_paint (&rect_whole);
}
// expand what's in the 320x200x1 frame buffer to the 320x200x4 SDL texture buffer
while (rects)
{
p0 = &sysvid_fb[rects->y * 320 + rects->x];
q0 = &screen_pixels[(rects->y * 320 + rects->x) * 4];
for (y = rects->y; y < rects->y + rects->height; y++)
{
p = p0;
q = q0;
for (x = rects->x; x < rects->x + rects->width; x++)
{
*(q + 0) = palette[*p][2]; // blue
*(q + 1) = palette[*p][1]; // green
*(q + 2) = palette[*p][0]; // red
*(q + 3) = 0; // alpha
q += 4;
p++;
}
q0 += 320 * 4;
p0 += 320;
}
rects = rects->next;
}
// now upscale with a little bit of magic
if (want_filter)
xbrz_scale (SCALE_FACTOR, (uint32_t *) screen_pixels, (uint32_t *) upscaled_pixels, 320, 200, false);
else
nearest_neighbor_scale ((uint32_t *) screen_pixels, 320, 200, (uint32_t *) upscaled_pixels, 320 * SCALE_FACTOR, 200 * SCALE_FACTOR);
SDL_UpdateTexture (screen_texture, NULL, upscaled_pixels, 320 * SCALE_FACTOR * 4);
SDL_RenderClear (renderer);
SDL_RenderCopy (renderer, screen_texture, NULL, NULL);
SDL_RenderPresent (renderer);
}