/* * CGraphics.cpp * * Created on: 03.05.2009 * Author: gerstrong * * This file contains low- to mid-level graphics functions, * which are NOT platform-specific. All the low-level stuff in * here is stuff that draws to the scroll buffer (and so is * not platform-specific). */ #include "keen.h" //#include "externals.h" #include "CGraphics.h" #include "sdl/CVideoDriver.h" #include "sdl/video/colourtable.h" #include "sdl/CVideoDriver.h" #include "CLogFile.h" #include "StringUtils.h" CGraphics::CGraphics() { HQBitmap = NULL; scrollbuffer=NULL; blitbuffer=NULL; scrollbuf_memsize = 0; blitbuf_memsize = 0; } CGraphics::~CGraphics() { // TODO Auto-generated destructor stub } bool CGraphics::allocScrollBufmem(void) { scrollbuf_memsize = 512*(512+300); // First I have to check the resolution and then evaluate the scroll buffer size blitbuf_memsize = (320)*(200+30); g_pLogFile->ftextOut("allocmem(): allocating %d bytes for scroll buffer...", scrollbuf_memsize); scrollbuffer = new Uint8[scrollbuf_memsize]; memset(scrollbuffer,COLOUR_MASK,scrollbuf_memsize); if (!scrollbuffer) { g_pLogFile->textOut(RED,"Failure
"); return false; } else g_pLogFile->textOut("OK
"); if (g_pVideoDriver->getZoomValue() > 1) { g_pLogFile->ftextOut("allocmem(): allocating %d bytes for blit buffer...", blitbuf_memsize); blitbuffer = new unsigned char[blitbuf_memsize]; if (!blitbuffer) { g_pLogFile->ftextOut(RED,"Failure
"); return false; } else g_pLogFile->ftextOut("OK
"); } return true; } void CGraphics::freemem(void) { if (scrollbuffer) { delete[] scrollbuffer; scrollbuffer = NULL; g_pLogFile->fltextOut(BLACK,true," Scrollbuffer memory released to system.
"); } if (blitbuffer) { delete[] blitbuffer; blitbuffer = NULL; g_pLogFile->fltextOut(BLACK,true," Blitbuffer memory released to system.
"); } } void CGraphics::sb_setpixel(int x, int y, unsigned char c) { scrollbuffer[(y<<9) + x] = c; } unsigned char CGraphics::sb_getpixel(int x, int y) { return scrollbuffer[(y<<9) + x]; } // draw a tile directly to the display (bypass the scroll buffer) void CGraphics::drawTile_direct(int x, int y, unsigned int t) { unsigned char xa,ya; for(ya=0;ya<16;ya++) for(xa=0;xa<16;xa++) g_pVideoDriver->setpixel(x+xa, y+ya, tiledata[t][ya][xa]); } // draws a sprite directly to the display (only used by status window) void CGraphics::drawSprite_direct(int x, int y, unsigned int t) { unsigned char xa,ya; unsigned char oldpixel; // used for the or operation when drawing maked sprites for(ya=0;yagetpixel(x+xa, y+ya); g_pVideoDriver->setpixel(x+xa, y+ya, (oldpixel | sprites[t].imgdata[ya][xa]) ); } else g_pVideoDriver->setpixel(x+xa, y+ya, (sprites[t].imgdata[ya][xa]==0) ? 16 : sprites[t].imgdata[ya][xa]); } void CGraphics::drawTile(int x, int y, unsigned int t) { if(HQBitmap) { unsigned char *offset = &scrollbuffer[(y<<9)+x]; unsigned char ya; // Tile in which the player won't interact, are to be ignored! if((TileProperty[t][BEHAVIOR] == 0 && TileProperty[t][ANIMATION] <= 1) || (TileProperty[t][BEHAVIOR] > 30) ) { for(ya=0;ya<16;ya++) { memset(offset, COLOUR_MASK, 16); offset+=512; } } else { for(ya=0;ya<16;ya++) { memcpy(offset, &tiledata[t][ya][0], 16); offset+=512; } } } else { unsigned char *offset = &scrollbuffer[(y<<9)+x]; unsigned char ya; for(ya=0;ya<16;ya++) { memcpy(offset, &tiledata[t][ya][0], 16); offset+=512; } } } // draws a masked tile ("til") to the scrollbuffer. // adjusts based on the X&Y scroll so that when the buffer is blitted // the tile will appear at (x,y). only pixels which have a corresponding // black pixel in tile "tmask" will be drawn. void CGraphics::drawTilewithmask(int x, int y, unsigned int til, unsigned int tmask) { unsigned char xa,ya; unsigned int bufoffX,bufoffY; unsigned int xstart,ystart; // clip the tile if (x>320 || y>200) return; if (x<-16||y<-16) return; if (x<0) xstart=-x; else xstart = 0; if (y<0) ystart=-y; else ystart = 0; bufoffY = ((y+ystart+scrolly_buf)&511)<<9; // points to start of line for(ya=ystart;ya<16;ya++) { bufoffX = (x+xstart+scrollx_buf)&511; // offset within line for(xa=xstart;xa<16;xa++) { if (tiledata[tmask][ya][xa] != 15) { scrollbuffer[bufoffY+bufoffX] = tiledata[til][ya][xa]; } bufoffX = (bufoffX+1)&511; } // move to next line and wrap to top of buffer if needed bufoffY += 512; if (bufoffY >= (512*512)) bufoffY = 0; } } // draws a tile ("til") to the scrollbuffer. adjusts based on the X&Y scroll // so that when the buffer is blitted the tile will appear at (x,y). // used for priority tiles (tiles[].priority) void CGraphics::drawPrioritytile(int x, int y, unsigned int til) { unsigned char xa,ya; unsigned int bufoffX,bufoffY; unsigned int xstart,ystart; // clip the tile if (x>320 || y>200) return; if (x<-16 || y<-16) return; if (x<0) xstart=-x; else xstart = 0; if (y<0) ystart=-y; else ystart = 0; bufoffY = ((y+ystart+scrolly_buf)&511)<<9; // points to start of line if(HQBitmap) { for(ya=ystart;ya<16;ya++) { bufoffX = (x+xstart+scrollx_buf)&511; // offset within line for(xa=xstart;xa<16;xa++) { scrollbuffer[bufoffY+bufoffX] = COLOUR_MASK; bufoffX = (bufoffX+1)&511; } // move to next line and wrap to top of buffer if needed bufoffY += 512; if (bufoffY >= (512*512)) bufoffY = 0; } return; } for(ya=ystart;ya<16;ya++) { bufoffX = (x+xstart+scrollx_buf)&511; // offset within line for(xa=xstart;xa<16;xa++) { scrollbuffer[bufoffY+bufoffX] = tiledata[til][ya][xa]; bufoffX = (bufoffX+1)&511; } // move to next line and wrap to top of buffer if needed bufoffY += 512; if (bufoffY >= (512*512)) bufoffY = 0; } } // draws a sprite to the scrollbuffer. // adjusts based on the X&Y scroll so that when the buffer is blitted // the sprite will appear at (x,y). saves the image beneath the sprite // into the erasedata[] of object objectnum. void CGraphics::drawSprite(int x, int y, unsigned int s, int objectnum) { unsigned char xa,ya; unsigned int bufoffX, bufoffY; unsigned int xstart,ystart; // clip the sprite if (x>320 || y>200) return; if (x<-sprites[s].xsize||y<-sprites[s].ysize) return; // if sprite is partially off the top or left of the screen, invert // the sign on the coordinate to make it positive, and start drawing // the sprite from there. if (x<0) xstart=-x; else xstart = 0; if (y<0) ystart=-y; else ystart = 0; bufoffY = ((y+ystart+scrolly_buf)&511)<<9; // points to start of line for(ya=ystart;ya= (512*512)) bufoffY = 0; } } // complement of drawsprite(). uses the saved image in objectnum to erase // a previously-drawn sprite. void CGraphics::eraseSprite(int x, int y, unsigned int s, int objectnum) { unsigned char xa,ya; unsigned int bufoffX, bufoffY; unsigned int xstart,ystart; // clip the sprite if (x>320 || y>200) return; if (x<-sprites[s].xsize||y<-sprites[s].ysize) return; // if sprite is partially off the top or left of the screen, invert // the sign on the coordinate to make it positive, and start drawing // the sprite from there. if (x<0) xstart=-x; else xstart = 0; if (y<0) ystart=-y; else ystart = 0; bufoffY = ((y+ystart+scrolly_buf)&511)<<9; // points to start of line for(ya=ystart;ya= (512*512)) bufoffY = 0; } } void CGraphics::drawCharacter(int x, int y, int f) { assert(f >= 0 && f < 256); unsigned char xa,ya; for(ya=0;ya<8;ya++) { for(xa=0;xa<8;xa++) { g_pVideoDriver->setpixel(x+xa, y+ya, font[f][ya][xa]); } } } void CGraphics::drawCharacter(float x, float y, int f) { assert(f >= 0 && f < 256); unsigned char xa,ya; for(ya=0;ya<8;ya++) { for(xa=0;xa<8;xa++) { g_pVideoDriver->setpixel((unsigned int)((x*320)+xa), (unsigned int)((y*200)+ya), (unsigned char)font[f][ya][xa]); } } } void CGraphics::sb_drawCharacter(int x, int y, int f) { unsigned char xa,ya; unsigned int yb; for(ya=0;ya<8;ya++) { yb = ((y+ya+scrolly_buf)&511)<<9; for(xa=0;xa<8;xa++) { scrollbuffer[yb+((x+xa+scrollx_buf)&511)] = font[f][ya][xa]; } } } void CGraphics::sb_drawCharacterwithmask(int x, int y, int f, char mask) { unsigned char xa,ya; unsigned int yb; for(ya=0;ya<8;ya++) { yb = ((y+ya+scrolly_buf)&511)<<9; for(xa=0;xa<8;xa++) { if(font[f][ya][xa] != mask) scrollbuffer[yb+((x+xa+scrollx_buf)&511)] = font[f][ya][xa]; } } } void CGraphics::sb_drawColorcharacter(int x, int y, int f, unsigned short colour, unsigned short bgcolour) { unsigned char xa,ya; unsigned int yb; for(ya=0;ya<8;ya++) { yb = ((y+ya+scrolly_buf)&511)<<9; for(xa=0;xa<8;xa++) { if(font[f][ya][xa] == 16) scrollbuffer[yb+((x+xa+scrollx_buf)&511)] = colour; else if(bgcolour != COLOUR_MASK) scrollbuffer[yb+((x+xa+scrollx_buf)&511)] = bgcolour; } } } unsigned char savebuf[200][320]; void CGraphics::saveArea(int x1, int y1, int x2, int y2) { unsigned char xa,ya; unsigned int yb; for(ya=0;yastart()) { printf("Graphics_Start(): VidDrv_Start() failed to initilize display
"); return 1; } // set up the palette g_pLogFile->ftextOut("Graphics_Start(): configuring palette.
"); initPalette(0); fadePalette(0); return 0; } void CGraphics::stopGraphics(void) { // shut down the video driver g_pVideoDriver->stop(); } void CGraphics::configPalette(int c, int r, int g, int b) { palette[c].r = r; palette[c].g = g; palette[c].b = b; } // loads the EGA palette into the palette[] array. if dark=1, loads in // the palette used when the lights are off (in ep2) void CGraphics::initPalette(int dark) { if (!dark) { configPalette(0, 0x00,0x00,0x00); configPalette(1, 0x00,0x00,0xa8); configPalette(2, 0x00,0xa8,0x00); configPalette(3, 0x00,0xa8,0xa8); configPalette(4, 0xa8,0x00,0x00); configPalette(5, 0xa8,0x00,0xa8); configPalette(6, 0xa8,0x54,0x00); configPalette(7, 0xa8,0xa8,0xa8); configPalette(8, 0x54,0x54,0x54); configPalette(9, 0x54,0x54,0xfc); configPalette(10, 0x54,0xfc,0x54); configPalette(11, 0x54,0xfc,0xfc); configPalette(12, 0xfc,0x54,0x54); configPalette(13, 0xfc,0x54,0xfc); configPalette(14, 0xfc,0xfc,0x54); configPalette(15, 0xfc,0xfc,0xfc); } else { configPalette(0, 0x00,0x00,0x00); configPalette(1, 0x00,0x00,0x00); configPalette(2, 0x00,0x00,0x00); configPalette(3, 0x00,0x00,0x00); configPalette(4, 0x00,0x00,0x00); configPalette(5, 0x00,0x00,0x00); configPalette(6, 0x00,0x00,0x00); configPalette(7, 0x54,0x54,0x54); configPalette(8, 0x00,0x00,0x00); configPalette(9, 0x00,0x00,0xa8); configPalette(10, 0x00,0xa8,0x00); configPalette(11, 0x00,0xa8,0xa8); configPalette(12, 0xa8,0x00,0x00); configPalette(13, 0xa8,0x00,0xa8); configPalette(14, 0xa8,0x54,0x00); configPalette(15, 0xa8,0xa8,0xa8); } // 16 is black, for flashing during vorticon death sequence // (all black in the graphics is mapped to 16, then the border around // the screen is the only thing left at color 0, so we can change 0's // palette to change the border color) configPalette(16,0x00,0x00,0x00); } void CGraphics::fadePalette(int fadeamt) { int c; int r,g,b; for(c=0;c<17;c++) { r = palette[c].r; g = palette[c].g; b = palette[c].b; if (fadeamt != PAL_FADE_SHADES) { if ((c==0||c==16) && fadeamt > PAL_FADE_SHADES && fade_black) { r = 255 / (PAL_FADE_WHITEOUT - PAL_FADE_SHADES); r = (r * (fadeamt - (PAL_FADE_WHITEOUT - PAL_FADE_SHADES))); g = b = r; } else { r /= PAL_FADE_SHADES; g /= PAL_FADE_SHADES; b /= PAL_FADE_SHADES; r *= fadeamt; g *= fadeamt; b *= fadeamt; } if (r > 0xff) r = 0xff; if (g > 0xff) g = 0xff; if (b > 0xff) b = 0xff; } g_pVideoDriver->pal_set(c, r, g, b); } if(HQBitmap) HQBitmap->setAlphaBlend(static_cast (fadeamt)); g_pVideoDriver->pal_apply(); } void CGraphics::drawBitmap(int xa, int ya, int b) { int x,y; unsigned char *bmdataptr; // for "b" arguments passed from GetBitmapNumberFromName(), // in case the specified name was not found if (b==-1) return; bmdataptr = bitmaps[b].bmptr; for(y=0;ysetpixel((x+xa+scrollx_buf-130)&511,(y+ya+scrolly_buf-30)&511,*bmdataptr); bmdataptr++; } } } int CGraphics::getBitmapNumberFromName(const char *bmname) { int i; for(i=0;igetBGLayerSurface()->w; srcrect.h = g_pVideoDriver->getBGLayerSurface()->h; HQBitmap->updateHQBitmap(g_pVideoDriver->getBGLayerSurface(), &srcrect, NULL); } } void CGraphics::loadHQGraphics(unsigned char episode, unsigned char level, const std::string& datadir) { SDL_Rect screen_rect; std::string buf = formatPathString(datadir); std::string buf2 = buf + "level" + itoa(level) + "ep" + itoa(episode) + ".bmp"; screen_rect.x = 0; screen_rect.y = 0; screen_rect.w = g_pVideoDriver->getWidth(); screen_rect.h = g_pVideoDriver->getHeight(); HQBitmap = new CHQBitmap(screen_rect); if(!HQBitmap->loadImage(buf2, (int) map.xsize, (int) map.ysize)) { delete HQBitmap; HQBitmap = NULL; return; } // Check if the tile have grey pixels in some tiles and remove them! for(int t=0 ; t < numtiles ; t++) { if(TileProperty[t][BEHAVIOR] > 0) { for(int xa=0 ; xa < 16 ; xa++) { for(int ya=0 ; ya < 16 ; ya++) { if(tiledata[t][ya][xa] == COLOUR_GREY) // Which should be masked. In Episode 1 it is gray { tiledata[t][ya][xa] = COLOUR_MASK; } } } } } } void CGraphics::unloadHQGraphics() { if(!HQBitmap) return; delete HQBitmap; HQBitmap = NULL; // Make unmask some tiles adding the original pixels back! for(int t=0 ; t < numtiles ; t++) { if(TileProperty[t][BEHAVIOR] > 0) { for(int xa=0 ; xa < 16 ; xa++) { for(int ya=0 ; ya < 16 ; ya++) { if(tiledata[t][ya][xa] == COLOUR_MASK) // Which should be masked. In Episode 1 it is gray { tiledata[t][ya][xa] = COLOUR_GREY; } } } } } }