Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
629 lines (521 sloc)
17.3 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| ** Oricutron | |
| ** Copyright (C) 2009-2014 Peter Gordon | |
| ** | |
| ** This program is free software; you can redistribute it and/or | |
| ** modify it under the terms of the GNU General Public License | |
| ** as published by the Free Software Foundation, version 2 | |
| ** of the License. | |
| ** | |
| ** This program is distributed in the hope that it will be useful, | |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| ** GNU General Public License for more details. | |
| ** | |
| ** You should have received a copy of the GNU General Public License | |
| ** along with this program; if not, write to the Free Software | |
| ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| ** | |
| ** Software rendering | |
| */ | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "system.h" | |
| #include "6502.h" | |
| #include "via.h" | |
| #include "8912.h" | |
| #include "disk.h" | |
| #include "gui.h" | |
| #include "monitor.h" | |
| #include "6551.h" | |
| #include "machine.h" | |
| #include "render_sw.h" | |
| #include "ula.h" | |
| static struct SDL_Surface *screen; | |
| static Uint32 gpal[NUM_GUI_COLS]; | |
| static Uint32 pixel_size, offset_top; | |
| static Uint32 pal[8*2]; // Palette | |
| static Uint32 dpal[8*2]; | |
| static Uint8 *mgimg[NUM_GIMG]; | |
| extern SDL_bool fullscreen, hwsurface; | |
| static SDL_bool needclr; | |
| extern struct textzone *tz[NUM_TZ]; | |
| extern unsigned char sgpal[]; | |
| extern Uint8 oricpalette[]; | |
| extern struct guiimg gimgs[NUM_GIMG]; | |
| extern SDL_bool refreshstatus; | |
| // Our "lovely" hand-coded font | |
| extern unsigned char thefont[]; | |
| // Pointer on the char rendering function | |
| void (*printchar)( Uint8*, unsigned char, Uint32, Uint32, SDL_bool ); | |
| // Pointer on the guiimg conversion function | |
| SDL_bool (*guiimg_to_img)(Uint8** dst, const struct guiimg* src); | |
| // --- printchar template function -------------------------------------------- | |
| // Print a char onto a X-bit framebuffer, X being a power of 2 | |
| // ptr = where to draw it | |
| // ch = which char to draw | |
| // fcol = foreground colour | |
| // bcol = background colour | |
| // solidfont = use background colour | |
| #define DEFINE_printchar_X_bpp(BIT_DEPTH) \ | |
| static void printchar_ ## BIT_DEPTH ## bpp \ | |
| ( Uint8* ptr, unsigned char ch, Uint32 fcol, Uint32 bcol, SDL_bool solidfont ) \ | |
| { \ | |
| int x, y, mask; \ | |
| const Uint8 *src_byte; \ | |
| Uint ## BIT_DEPTH *dst_pixel; \ | |
| Uint8* dst_scanline; \ | |
| \ | |
| if( ch > 127 ) return; \ | |
| \ | |
| src_byte = &thefont[ch*12]; \ | |
| \ | |
| dst_scanline = ptr; \ | |
| \ | |
| for( y=12; y!=0; --y, ++src_byte, dst_scanline+=screen->pitch ) \ | |
| { \ | |
| dst_pixel = (Uint ## BIT_DEPTH *)dst_scanline; \ | |
| \ | |
| for( mask=0x80, x=8; x!=0; --x, ++dst_pixel, mask>>=1 ) \ | |
| { \ | |
| if( (*src_byte)&mask ) \ | |
| *dst_pixel = (Uint ## BIT_DEPTH)fcol; \ | |
| else if( solidfont ) \ | |
| *dst_pixel = (Uint ## BIT_DEPTH)bcol; \ | |
| } \ | |
| } \ | |
| } | |
| DEFINE_printchar_X_bpp(16) | |
| DEFINE_printchar_X_bpp(32) | |
| // --- end of printchar template function ------------------------------------- | |
| void render_begin_sw( struct machine *oric ) | |
| { | |
| int x, y; | |
| Uint8 *dst_scanline; | |
| if( SDL_MUSTLOCK( screen ) ) | |
| SDL_LockSurface( screen ); | |
| if( oric->newpopupstr ) | |
| { | |
| dst_scanline = (Uint8*)screen->pixels; | |
| dst_scanline += 320 * pixel_size; | |
| if( oric->sw_depth == 16 ) | |
| { | |
| Uint16 *dst_pixel; | |
| for( y=12; y!=0; --y, dst_scanline += screen->pitch) | |
| { | |
| dst_pixel = (Uint16 *)dst_scanline; | |
| for( x=320; x<640; x++, dst_pixel++ ) | |
| *dst_pixel = gpal[0]; | |
| } | |
| } else { | |
| Uint32 *dst_pixel; | |
| for( y=12; y!=0; --y, dst_scanline += screen->pitch) | |
| { | |
| dst_pixel = (Uint32 *)dst_scanline; | |
| for( x=320; x<640; x++, dst_pixel++ ) | |
| *dst_pixel = gpal[0]; | |
| } | |
| } | |
| oric->newpopupstr = SDL_FALSE; | |
| } | |
| if( oric->newstatusstr ) | |
| { | |
| refreshstatus = SDL_TRUE; | |
| oric->newstatusstr = SDL_FALSE; | |
| } | |
| } | |
| void render_end_sw( struct machine *oric ) | |
| { | |
| int i; | |
| Uint32 char_pitch; | |
| Uint8 *dst_pixel; | |
| char_pitch = 8 * pixel_size; | |
| if( oric->emu_mode == EM_RUNNING ) | |
| { | |
| if( oric->popupstr[0] ) | |
| { | |
| dst_pixel = (Uint8*)screen->pixels; | |
| dst_pixel += 320 * pixel_size; | |
| for( i=0; oric->popupstr[i]; i++, dst_pixel += char_pitch ) | |
| printchar( dst_pixel, oric->popupstr[i], gpal[1], gpal[0], SDL_TRUE ); | |
| } | |
| if( oric->statusstr[0] ) | |
| { | |
| dst_pixel = (Uint8*)screen->pixels; | |
| dst_pixel += 466 * screen->pitch; | |
| for( i=0; oric->statusstr[i]; i++, dst_pixel += char_pitch ) | |
| printchar( dst_pixel, oric->statusstr[i], gpal[1], 0, SDL_FALSE ); | |
| } | |
| } | |
| if( SDL_MUSTLOCK( screen ) ) | |
| SDL_UnlockSurface( screen ); | |
| SDL_COMPAT_Flip( screen ); | |
| } | |
| void render_textzone_alloc_sw( struct machine *oric, int i ) | |
| { | |
| } | |
| void render_textzone_free_sw( struct machine *oric, int i ) | |
| { | |
| } | |
| void render_textzone_sw( struct machine *oric, int i ) | |
| { | |
| int x, y, o; | |
| Uint32 char_pitch; | |
| struct textzone *ptz = tz[i]; | |
| Uint8 *dst_scanline, *dst_pixel; | |
| char_pitch = 8 * pixel_size; | |
| dst_scanline = (Uint8 *)screen->pixels; | |
| dst_scanline += screen->pitch * ptz->y + pixel_size * ptz->x; | |
| o = 0; | |
| for( y=ptz->h; y!=0; --y, dst_scanline+=12*screen->pitch ) | |
| { | |
| dst_pixel = dst_scanline; | |
| for( x=ptz->w; x!=0; --x, ++o, dst_pixel+=char_pitch ) | |
| printchar( dst_pixel, ptz->tx[o], gpal[ptz->fc[o]], gpal[ptz->bc[o]], SDL_TRUE ); | |
| } | |
| } | |
| // Clear an area to background | |
| void render_clear_area_sw( int x, int y, int w, int h ) | |
| { | |
| Uint8 *dst_scanline; | |
| Sint32 i; | |
| dst_scanline = (Uint8 *)screen->pixels; | |
| dst_scanline += screen->pitch * y + pixel_size * x; | |
| for( i=0; i<h; i++, dst_scanline+=screen->pitch ) | |
| memset( dst_scanline, 0, pixel_size*w ); | |
| } | |
| // Draw a GUI image at X,Y | |
| void render_gimg_sw( int img_id, Sint32 xp, Sint32 yp ) | |
| { | |
| struct guiimg *gi = &gimgs[img_id]; | |
| Uint8 *src_scanline, *dst_scanline; | |
| Sint32 i; | |
| src_scanline = mgimg[img_id]; | |
| dst_scanline = (Uint8 *)screen->pixels; | |
| dst_scanline += screen->pitch * yp + pixel_size * xp; | |
| for( i=gi->h; i!=0; --i, src_scanline+=pixel_size*gi->w, dst_scanline+=screen->pitch ) | |
| memcpy( dst_scanline, src_scanline, pixel_size*gi->w ); | |
| } | |
| // Draw part of an image (xp,yp = screen location, ox, oy = offset into image, w, h = dimensions) | |
| void render_gimgpart_sw( int img_id, Sint32 xp, Sint32 yp, Sint32 ox, Sint32 oy, Sint32 w, Sint32 h ) | |
| { | |
| struct guiimg *gi = &gimgs[img_id]; | |
| Uint8 *src_scanline, *dst_scanline; | |
| Sint32 i; | |
| src_scanline = mgimg[img_id]; | |
| src_scanline += pixel_size*(gi->w * oy + ox); | |
| dst_scanline = (Uint8 *)screen->pixels; | |
| dst_scanline += screen->pitch * yp + pixel_size * xp; | |
| for( i=h; i!=0; --i, src_scanline+=pixel_size*gi->w, dst_scanline+=screen->pitch ) | |
| memcpy( dst_scanline, src_scanline, pixel_size*w ); | |
| } | |
| // Copy the video output buffer to the SDL surface, assuming 16bpp video mode | |
| void render_video_sw_16bpp( struct machine *oric, SDL_bool doublesize ) | |
| { | |
| int x, y; | |
| Uint8 *src_pixel; | |
| Sint32 dst_pitch_x2; | |
| Uint32 c; | |
| Uint8 *dst_scanline, *dst_even_scanline, *dst_odd_scanline; | |
| Uint16 *dst_pixel; | |
| Uint32 *dst_even_pixel, *dst_odd_pixel; | |
| if( !oric->scr ) | |
| return; | |
| if( doublesize ) | |
| { | |
| if( needclr ) | |
| { | |
| SDL_FillRect(screen, NULL, gpal[0]); | |
| needclr = SDL_FALSE; | |
| } | |
| src_pixel = oric->scr; | |
| dst_pitch_x2 = 2 * screen->pitch; | |
| dst_even_scanline = ((Uint8*)screen->pixels) + offset_top; | |
| dst_odd_scanline = dst_even_scanline; | |
| dst_odd_scanline += screen->pitch; | |
| if( oric->scanlines ) | |
| { | |
| for( y=0; y<224; y++, dst_even_scanline+=dst_pitch_x2, dst_odd_scanline+=dst_pitch_x2 ) | |
| { | |
| if (!oric->vid_dirty[y]) | |
| { | |
| src_pixel += 240; | |
| continue; | |
| } | |
| dst_even_pixel = (Uint32*)dst_even_scanline; | |
| dst_odd_pixel = (Uint32*)dst_odd_scanline; | |
| for( x=240; x!=0; --x ) | |
| { | |
| c = *(src_pixel++); | |
| *(dst_even_pixel++) = dpal[c]; | |
| *(dst_odd_pixel++) = dpal[c+8]; | |
| } | |
| oric->vid_dirty[y] = SDL_FALSE; | |
| } | |
| } else { | |
| for( y=0; y<224; y++, dst_even_scanline+=dst_pitch_x2, dst_odd_scanline+=dst_pitch_x2 ) | |
| { | |
| if (!oric->vid_dirty[y]) | |
| { | |
| src_pixel += 240; | |
| continue; | |
| } | |
| dst_even_pixel = (Uint32*)dst_even_scanline; | |
| dst_odd_pixel = (Uint32*)dst_odd_scanline; | |
| for( x=240; x!=0; --x ) | |
| { | |
| c = dpal[*(src_pixel++)]; | |
| *(dst_even_pixel++) = c; | |
| *(dst_odd_pixel++) = c; | |
| } | |
| oric->vid_dirty[y] = SDL_FALSE; | |
| } | |
| } | |
| return; | |
| } | |
| needclr = SDL_TRUE; | |
| src_pixel = oric->scr; | |
| dst_scanline = (Uint8*)screen->pixels; | |
| for( y=0; y<4; y++ ) | |
| { | |
| memset( dst_scanline, 0, 240*pixel_size ); | |
| dst_scanline += screen->pitch; | |
| } | |
| for( ; y<228; y++, dst_scanline+=screen->pitch ) | |
| { | |
| dst_pixel = (Uint16*)dst_scanline; | |
| for( x=240; x!=0; --x ) | |
| *(dst_pixel++) = (Uint16)pal[*(src_pixel++)]; | |
| } | |
| } | |
| // Copy the video output buffer to the SDL surface, assuming 32bpp video mode | |
| void render_video_sw_32bpp( struct machine *oric, SDL_bool doublesize ) | |
| { | |
| int x, y; | |
| Uint8 *src_pixel; | |
| Sint32 dst_pitch_x2; | |
| Uint32 c, c2; | |
| Uint8 *dst_scanline, *dst_even_scanline, *dst_odd_scanline; | |
| Uint32 *dst_pixel, *dst_even_pixel, *dst_odd_pixel; | |
| if( !oric->scr ) | |
| return; | |
| if( doublesize ) | |
| { | |
| if( needclr ) | |
| { | |
| SDL_FillRect(screen, NULL, gpal[0]); | |
| needclr = SDL_FALSE; | |
| } | |
| src_pixel = oric->scr; | |
| dst_pitch_x2 = 2 * screen->pitch; | |
| dst_even_scanline = ((Uint8*)screen->pixels) + offset_top; | |
| dst_odd_scanline = dst_even_scanline; | |
| dst_odd_scanline += screen->pitch; | |
| if( oric->scanlines ) | |
| { | |
| for( y=0; y<224; y++, dst_even_scanline+=dst_pitch_x2, dst_odd_scanline+=dst_pitch_x2 ) | |
| { | |
| if (!oric->vid_dirty[y]) | |
| { | |
| src_pixel += 240; | |
| continue; | |
| } | |
| dst_even_pixel = (Uint32*)dst_even_scanline; | |
| dst_odd_pixel = (Uint32*)dst_odd_scanline; | |
| for( x=240; x!=0; --x ) | |
| { | |
| c2 = pal[(*src_pixel)+8]; | |
| c = pal[*(src_pixel++)]; | |
| *(dst_even_pixel++) = c; | |
| *(dst_even_pixel++) = c; | |
| *(dst_odd_pixel++) = c2; | |
| *(dst_odd_pixel++) = c2; | |
| } | |
| oric->vid_dirty[y] = SDL_FALSE; | |
| } | |
| } else { | |
| for( y=0; y<224; y++, dst_even_scanline+=dst_pitch_x2, dst_odd_scanline+=dst_pitch_x2 ) | |
| { | |
| if (!oric->vid_dirty[y]) | |
| { | |
| src_pixel += 240; | |
| continue; | |
| } | |
| dst_even_pixel = (Uint32*)dst_even_scanline; | |
| dst_odd_pixel = (Uint32*)dst_odd_scanline; | |
| for( x=240; x!=0; --x ) | |
| { | |
| c = pal[*(src_pixel++)]; | |
| *(dst_even_pixel++) = c; | |
| *(dst_even_pixel++) = c; | |
| *(dst_odd_pixel++) = c; | |
| *(dst_odd_pixel++) = c; | |
| } | |
| oric->vid_dirty[y] = SDL_FALSE; | |
| } | |
| } | |
| return; | |
| } | |
| needclr = SDL_TRUE; | |
| src_pixel = oric->scr; | |
| dst_scanline = (Uint8*)screen->pixels; | |
| for( y=0; y<4; y++ ) | |
| { | |
| memset( dst_scanline, 0, 240*pixel_size ); | |
| dst_scanline += screen->pitch; | |
| } | |
| for( ; y<228; y++, dst_scanline+=screen->pitch ) | |
| { | |
| dst_pixel = (Uint32*)dst_scanline; | |
| for( x=240; x!=0; --x ) | |
| *(dst_pixel++) = pal[*(src_pixel++)]; | |
| } | |
| } | |
| void render_sw_detectvideo( struct machine *oric ) | |
| { | |
| #ifndef __ANDROID__ | |
| int BitsPerPixel = SDL_COMPAT_GetBitsPerPixel(); | |
| // Guess the suitable video mode, either 16bpp or 32bpp | |
| oric->sw_depth = 16; | |
| switch( BitsPerPixel ) | |
| { | |
| // Great, cases we handle | |
| case 8: | |
| case 16: | |
| case 24: | |
| case 32: | |
| oric->sw_depth = BitsPerPixel; | |
| break; | |
| // Damn, cases we don't handle. Let's say 16 bpp gonna be ok | |
| default: | |
| break; | |
| } | |
| #else | |
| oric->sw_depth = 32; | |
| #endif | |
| } | |
| void preinit_render_sw( struct machine *oric ) | |
| { | |
| Sint32 i; | |
| // Screen surface is not set yet | |
| screen = NULL; | |
| // Images are not set yet | |
| for( i=0; i<NUM_GIMG; i++ ) | |
| mgimg[i] = NULL; | |
| } | |
| SDL_bool render_togglefullscreen_sw( struct machine *oric ) | |
| { | |
| #if defined(__amigaos4__) || defined(__linux__) || defined(__MORPHOS__) | |
| // Use SDL_WM_ToggleFullScreen on systems where it is supported | |
| if( SDL_COMPAT_WM_ToggleFullScreen( screen ) ) | |
| { | |
| fullscreen = !fullscreen; | |
| return SDL_TRUE; | |
| } | |
| return SDL_FALSE; | |
| #else | |
| oric->shut_render( oric ); | |
| fullscreen = !fullscreen; | |
| if( oric->init_render( oric ) ) return SDL_TRUE; | |
| set_render_mode( oric, RENDERMODE_NULL ); | |
| oric->emu_mode = EM_PLEASEQUIT; | |
| return SDL_FALSE; | |
| #endif | |
| } | |
| // --- guiimg_to_img_X_bpp template function ---------------------------------- | |
| #define DEFINE_guiimg_to_img_X_bpp(BIT_DEPTH) \ | |
| static SDL_bool guiimg_to_img_ ## BIT_DEPTH ## bpp \ | |
| (Uint8** dst, const struct guiimg* src) \ | |
| { \ | |
| size_t i; \ | |
| const Uint8 *src_pixel; \ | |
| Uint ## BIT_DEPTH *dst_pixel; \ | |
| \ | |
| (*dst) = (Uint8 *)malloc( src->w*src->h*sizeof(Uint ## BIT_DEPTH) ); \ | |
| if ((*dst) == NULL) \ | |
| return SDL_FALSE; \ | |
| \ | |
| src_pixel = src->buf; \ | |
| dst_pixel = (Uint ## BIT_DEPTH *)(*dst); \ | |
| \ | |
| for( i=src->w*src->h; i!=0; --i, src_pixel += 3, ++dst_pixel ) \ | |
| (*dst_pixel) = \ | |
| (Uint ## BIT_DEPTH)SDL_MapRGB( screen->format, \ | |
| src_pixel[0], \ | |
| src_pixel[1], \ | |
| src_pixel[2] ); \ | |
| \ | |
| return SDL_TRUE; \ | |
| } | |
| DEFINE_guiimg_to_img_X_bpp(16) | |
| DEFINE_guiimg_to_img_X_bpp(32) | |
| // --- end of guiimg_to_img_X_bpp template function --------------------------- | |
| SDL_bool init_render_sw( struct machine *oric ) | |
| { | |
| int i; | |
| unsigned char* pal_it; | |
| Sint32 surfacemode; | |
| pixel_size = oric->sw_depth / 8; | |
| surfacemode = fullscreen ? SDL_COMPAT_FULLSCREEN : SDL_SWSURFACE; | |
| if( hwsurface ) { surfacemode &= ~SDL_SWSURFACE; surfacemode |= SDL_COMPAT_HWSURFACE; } | |
| // Try to setup the video display | |
| if (oric->show_keyboard) { | |
| screen = SDL_COMPAT_SetVideoMode( 640, 480+240, oric->sw_depth, surfacemode ); | |
| } else { | |
| screen = SDL_COMPAT_SetVideoMode( 640, 480, oric->sw_depth, surfacemode ); | |
| } | |
| if( !screen ) | |
| { | |
| printf( "SDL video failed\n" ); | |
| return SDL_FALSE; | |
| } | |
| SDL_COMPAT_WM_SetCaption( APP_NAME_FULL, APP_NAME_FULL ); | |
| // Set the video bit depth dependent function | |
| if (oric->sw_depth == 16) { | |
| printchar = printchar_16bpp; | |
| guiimg_to_img = guiimg_to_img_16bpp; | |
| // SDL_COMPAT_WM_SetCaption( "16bit video", "16bit video" ); | |
| } | |
| else if (oric->sw_depth == 32) { | |
| printchar = printchar_32bpp; | |
| guiimg_to_img = guiimg_to_img_32bpp; | |
| // SDL_COMPAT_WM_SetCaption( "32bit video", "32bit video" ); | |
| } | |
| // Convert the GUI palette to the screen format bti depth | |
| pal_it = sgpal; | |
| for( i=0; i<NUM_GUI_COLS; i++, pal_it+=3 ) | |
| gpal[i] = SDL_MapRGB( screen->format, pal_it[0], pal_it[1], pal_it[2] ); | |
| // Convert the Oric palette to the screen format bti depth | |
| pal_it = oricpalette; | |
| for( i=0; i<8; i++, pal_it+=3 ) | |
| { | |
| pal[i ] = SDL_MapRGB( screen->format, pal_it[0], pal_it[1], pal_it[2] ); | |
| pal[i+8] = SDL_MapRGB( screen->format, pal_it[0]/2, pal_it[1]/2, pal_it[2]/2 ); | |
| } | |
| // Get the images for the GUI | |
| for( i=0; i<NUM_GIMG; i++ ) | |
| if (!guiimg_to_img(mgimg + i, gimgs + i)) | |
| return SDL_FALSE; | |
| // Precompute pixels pairs for efficient rendering in 16 bpp mode | |
| for( i=0; i<8*2; i++ ) | |
| dpal[i] = (pal[i]<<16)|pal[i]; | |
| // For the first frame rendered, we need to clean the screen | |
| needclr = SDL_TRUE; | |
| refreshstatus = SDL_TRUE; | |
| // Calculate the offset to render the screen | |
| offset_top = (240 - 226) * screen->pitch; | |
| offset_top += pixel_size * 80; | |
| ula_set_dirty( oric ); | |
| // Job done | |
| return SDL_TRUE; | |
| } | |
| void shut_render_sw( struct machine *oric ) | |
| { | |
| Sint32 i; | |
| for( i=0; i<NUM_GIMG; i++ ) | |
| { | |
| if( mgimg[i] ) free( mgimg[i] ); | |
| mgimg[i] = NULL; | |
| } | |
| // The surface will be freed by SDL_Quit, or a call to SDL_COMPAT_SetVideoMode from a different render module | |
| } |