/* * Copyright (C) 2002-2004 The DOSBox Team * * 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; either version 2 of the License, or * (at your option) any later version. * * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* $Id: render.cpp,v 1.25 2004/01/31 22:38:27 harekiet Exp $ */ #include #include #include #include #include "dosbox.h" #include "video.h" #include "render.h" #include "setup.h" #include "keyboard.h" #include "cross.h" #include "support.h" #define RENDER_MAXWIDTH 1280 #define RENDER_MAXHEIGHT 1024 struct PalData { struct { Bit8u red; Bit8u green; Bit8u blue; Bit8u unused; } rgb[256]; volatile Bitu first; volatile Bitu last; union { Bit32u bpp32[256]; Bit16u bpp16[256]; Bit32u yuv[256]; } lookup; }; static struct { struct { Bitu width; Bitu height; Bitu bpp; Bitu pitch; Bitu scalew; Bitu scaleh; double ratio; } src; struct { Bitu width; Bitu height; Bitu pitch; Bitu line; Bitu bpp; RENDER_Operation type; RENDER_Operation want_type; RENDER_Line_Handler line_handler; Bit8u * draw; Bit8u * buffer; Bit8u * pixels; } op; struct { Bitu count; Bitu max; } frameskip; PalData pal; struct { Bit8u hlines[RENDER_MAXHEIGHT]; } normal; #if (C_SSHOT) struct { RENDER_Operation type; Bitu bpp,width,height,line; const char * dir; Bit8u * buffer,* draw; bool usesrc; } shot; #endif bool active; bool aspect; bool updating; } render; Bit8u render_line_cache[4][RENDER_MAXWIDTH*4]; //Bit32u pixels RENDER_Line_Handler RENDER_DrawLine; Bit8u * RENDER_TempLine; /* Forward declerations */ static void RENDER_ResetPal(void); /* Include the different rendering routines */ #include "render_templates.h" #include "render_normal.h" #include "render_scale2x.h" #if (C_SSHOT) #include static void RENDER_ShotDraw(Bit8u * src) { if (render.shot.usesrc) { memcpy(render.shot.draw,src,render.shot.line); render.shot.draw+=render.shot.line; } else render.op.line_handler(src); } /* Take a screenshot of the data that should be rendered */ static void TakeScreenShot(Bit8u * bitmap) { Bitu last=0;char file_name[CROSS_LEN]; DIR * dir;struct dirent * dir_ent; png_structp png_ptr; png_infop info_ptr; png_bytep * row_pointers; png_color palette[256]; Bitu i; /* Find a filename to open */ dir=opendir(render.shot.dir); if (!dir) { LOG_MSG("Can't open snapshot directory %s",render.shot.dir); return; } while (dir_ent=readdir(dir)) { char tempname[CROSS_LEN]; strcpy(tempname,dir_ent->d_name); char * test=strstr(tempname,".png"); if (!test) continue; *test=0; if (strlen(tempname)<5) continue; if (strncmp(tempname,"snap",4)!=0) continue; Bitu num=atoi(&tempname[4]); if (num>=last) last=num+1; } closedir(dir); sprintf(file_name,"%s%csnap%04d.png",render.shot.dir,CROSS_FILESPLIT,last); /* Open the actual file */ FILE * fp=fopen(file_name,"wb"); if (!fp) { LOG_MSG("Can't open file %s for snapshot",file_name); return; } /* First try to alloacte the png structures */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); if (!png_ptr) return; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr,(png_infopp)NULL); return; } /* Finalize the initing of png library */ png_init_io(png_ptr, fp); png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); /* set other zlib parameters */ png_set_compression_mem_level(png_ptr, 8); png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); png_set_compression_window_bits(png_ptr, 15); png_set_compression_method(png_ptr, 8); png_set_compression_buffer_size(png_ptr, 8192); if (render.shot.bpp==8) { png_set_IHDR(png_ptr, info_ptr, render.shot.width, render.shot.height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); for (i=0;i<256;i++) { palette[i].red=render.pal.rgb[i].red; palette[i].green=render.pal.rgb[i].green; palette[i].blue=render.pal.rgb[i].blue; } png_set_PLTE(png_ptr, info_ptr, palette,256); } else { png_set_IHDR(png_ptr, info_ptr, render.shot.width, render.shot.height, render.shot.bpp, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } /*Allocate an array of scanline pointers*/ row_pointers=(png_bytep*)malloc(render.shot.height*sizeof(png_bytep)); for (i=0;irender.pal.last) return; Bitu i; switch (render.op.bpp) { case 8: GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]); break; case 16: for (i=render.pal.first;i<=render.pal.last;i++) { Bit8u r=render.pal.rgb[i].red; Bit8u g=render.pal.rgb[i].green; Bit8u b=render.pal.rgb[i].blue; render.pal.lookup.bpp16[i]=GFX_GetRGB(r,g,b); } break; case 24: case 32: for (i=render.pal.first;i<=render.pal.last;i++) { Bit8u r=render.pal.rgb[i].red; Bit8u g=render.pal.rgb[i].green; Bit8u b=render.pal.rgb[i].blue; render.pal.lookup.bpp32[i]=GFX_GetRGB(r,g,b); } break; } /* Setup pal index to startup values */ render.pal.first=256; render.pal.last=0; } static void RENDER_ResetPal(void) { render.pal.first=0; render.pal.last=255; } void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) { render.pal.rgb[entry].red=red; render.pal.rgb[entry].green=green; render.pal.rgb[entry].blue=blue; if (render.pal.first>entry) render.pal.first=entry; if (render.pal.last1.0) gfx_scaleh*=render.src.ratio; else gfx_scalew*=(1/render.src.ratio); Bitu gfx_flags; Bitu bpp=GFX_GetBestMode(render.src.bpp,gfx_flags); Bitu index; switch (bpp) { case 8: index=0;break; case 16:index=1;break; case 24:index=2;break; case 32:index=3;break; } /* Initial scaler testing */ switch (render.op.want_type) { case OP_Normal2x: case OP_None: render.op.type=render.op.want_type; normalop: if (gfx_flags & GFX_HASSCALING) { gfx_scalew*=scalew; gfx_scaleh*=scaleh; render.op.line_handler=Normal_8[index]; for (Bitu i=0;i1 && (render.op.type==OP_None)) { render.op.line_handler=Normal_8[index]; scalew>>=1;gfx_scaleh/=2; } else { render.op.line_handler=Normal_2x_8[index]; } } else render.op.line_handler=Normal_8[index]; width*=scalew; double lines=0.0; height=0; for (Bitu i=0;i0) ? temp_lines-1 : 0; height+=temp_lines; } } break; case OP_AdvMame2x: if (scalew!=2){ render.op.type=OP_Normal2x; goto normalop; } if (gfx_flags & GFX_HASSCALING) { height=scaleh*height; } else { height=(Bitu)(gfx_scaleh*scaleh*height); } width<<=1; { Bits i; double src_add=(double)height/(double)render.src.height; double src_index=0; double src_lines=0; Bitu src_done=0; Bitu height=0; am2x.cmd_index=am2x.cmd_data; am2x.buf_pos=0;am2x.buf_used=0; for (i=0;i<=(Bits)render.src.height;i++) { src_lines+=src_add; Bitu lines=(Bitu)src_lines; src_lines-=lines; switch (lines) { case 0: break; case 1: AdvMame2x_AddLine(i,i,i); break; case 2: AdvMame2x_AddLine(i-1,i,i+1); AdvMame2x_AddLine(i+1,i,i-1); break; default: AdvMame2x_AddLine(i-1,i,i+1); for (lines-=2;lines>0;lines--) AdvMame2x_AddLine(i,i,i); AdvMame2x_AddLine(i+1,i,i-1); break; } AdvMame2x_CheckLines(i); } render.op.line_handler=AdvMame2x_8_Table[index]; } break; } render.op.bpp=bpp; render.op.width=width; render.op.height=height; GFX_SetSize(width,height,bpp,gfx_scalew,gfx_scaleh,&RENDER_ReInit); RENDER_ResetPal(); render.active=true; } void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,double ratio,Bitu scalew,Bitu scaleh) { if ((!width) || (!height) || (!pitch)) { render.active=false; return; } render.src.width=width; render.src.height=height; render.src.bpp=bpp; render.src.pitch=pitch; render.src.ratio=render.aspect ? ratio : 1.0; render.src.scalew=scalew; render.src.scaleh=scaleh; RENDER_ReInit(); } extern void GFX_SetTitle(Bits cycles, Bits frameskip); static void IncreaseFrameSkip(void) { if (render.frameskip.max<10) render.frameskip.max++; LOG_MSG("Frame Skip at %d",render.frameskip.max); GFX_SetTitle(-1,render.frameskip.max); } static void DecreaseFrameSkip(void) { if (render.frameskip.max>0) render.frameskip.max--; LOG_MSG("Frame Skip at %d",render.frameskip.max); GFX_SetTitle(-1,render.frameskip.max); } void RENDER_Init(Section * sec) { Section_prop * section=static_cast(sec); render.pal.first=256; render.pal.last=0; render.aspect=section->Get_bool("aspect"); render.frameskip.max=section->Get_int("frameskip"); render.frameskip.count=0; render.updating=true; #if (C_SSHOT) render.shot.dir=section->Get_string("snapdir"); render.shot.usesrc=true; KEYBOARD_AddEvent(KBD_f5,KBD_MOD_CTRL,EnableScreenShot); #endif const char * scaler;std::string cline; if (control->cmdline->FindString("-scaler",cline,false)) { scaler=cline.c_str(); } else { scaler=section->Get_string("scaler"); } if (!strcasecmp(scaler,"none")) render.op.want_type=OP_None; else if (!strcasecmp(scaler,"normal2x")) render.op.want_type=OP_Normal2x; else if (!strcasecmp(scaler,"advmame2x")) render.op.want_type=OP_AdvMame2x; else { render.op.want_type=OP_None; LOG_MSG("Illegal scaler type %s,falling back to none.",scaler); } KEYBOARD_AddEvent(KBD_f7,KBD_MOD_CTRL,DecreaseFrameSkip); KEYBOARD_AddEvent(KBD_f8,KBD_MOD_CTRL,IncreaseFrameSkip); GFX_SetTitle(-1,render.frameskip.max); }