Path: blob/main/RSDKv4/Drawing.cpp
817 views
#include "RetroEngine.hpp"12ushort blendLookupTable[0x20 * 0x100];3ushort subtractLookupTable[0x20 * 0x100];4ushort tintLookupTable[0x10000];56// Extras used in blending7#define maxVal(a, b) (a >= b ? a : b)8#define minVal(a, b) (a <= b ? a : b)910bool windowCreated = false;1112int SCREEN_XSIZE_CONFIG = 424;13int SCREEN_XSIZE = 424;14int SCREEN_CENTERX = 424 / 2;1516float SCREEN_XSIZE_F = 424;17float SCREEN_CENTERX_F = 424 / 2;1819float SCREEN_YSIZE_F = SCREEN_YSIZE;20float SCREEN_CENTERY_F = SCREEN_YSIZE / 2;2122int touchWidth = SCREEN_XSIZE;23int touchHeight = SCREEN_YSIZE;24float touchWidthF = SCREEN_XSIZE;25float touchHeightF = SCREEN_YSIZE;2627DrawListEntry drawListEntries[DRAWLAYER_COUNT];2829int gfxDataPosition = 0;30GFXSurface gfxSurface[SURFACE_COUNT];31byte graphicData[GFXDATA_SIZE];3233DisplaySettings displaySettings;34bool convertTo32Bit = false;35bool mixFiltersOnJekyll = false;3637#if RETRO_USING_OPENGL38GLint defaultFramebuffer = -1;39GLuint framebufferHiRes = -1;40GLuint renderbufferHiRes = -1;41#endif4243#if !RETRO_USE_ORIGINAL_CODE44// enable integer scaling, which is a modification of enhanced scaling45bool integerScaling = false;46// allows me to disable it to prevent blur on resolutions that match only on 1 axis47bool disableEnhancedScaling = false;48// enable bilinear scaling, which just disables the fancy upscaling that enhanced scaling does.49bool bilinearScaling = false;50#endif5152int InitRenderDevice()53{54char gameTitle[0x40];5556sprintf(gameTitle, "%s%s", Engine.gameWindowText, Engine.usingDataFile_Config ? "" : " (Using Data Folder)");5758#if !RETRO_USE_ORIGINAL_CODE59#if RETRO_USING_SDL260SDL_Init(SDL_INIT_EVERYTHING);6162SDL_DisableScreenSaver();6364SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");65SDL_SetHint(SDL_HINT_RENDER_VSYNC, Engine.vsync ? "1" : "0");6667byte flags = 0;68#if RETRO_USING_OPENGL69flags |= SDL_WINDOW_OPENGL;7071#if RETRO_PLATFORM != RETRO_OSX // dude idk either you just gotta trust that this works72#if RETRO_PLATFORM != RETRO_ANDROID73SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);74#else75SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);76#endif77SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);78SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);79SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);80SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);81#endif82#endif83#if RETRO_DEVICETYPE == RETRO_MOBILE84Engine.startFullScreen = true;8586SDL_DisplayMode dm;87SDL_GetDesktopDisplayMode(0, &dm);8889bool landscape = dm.h < dm.w;90int h = landscape ? dm.w : dm.h;91int w = landscape ? dm.h : dm.w;9293SCREEN_XSIZE = ((float)SCREEN_YSIZE * h / w);94if (SCREEN_XSIZE % 2)95++SCREEN_XSIZE;96#endif9798SCREEN_CENTERX = SCREEN_XSIZE / 2;99Engine.window = SDL_CreateWindow(gameTitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_XSIZE * Engine.windowScale,100SCREEN_YSIZE * Engine.windowScale, SDL_WINDOW_ALLOW_HIGHDPI | flags);101102if (!Engine.window) {103PrintLog("ERROR: failed to create window!");104return 0;105}106107#if !RETRO_USING_OPENGL108Engine.renderer = SDL_CreateRenderer(Engine.window, -1, SDL_RENDERER_ACCELERATED);109110if (!Engine.renderer) {111PrintLog("ERROR: failed to create renderer!");112return 0;113}114115SDL_RenderSetLogicalSize(Engine.renderer, SCREEN_XSIZE, SCREEN_YSIZE);116SDL_SetRenderDrawBlendMode(Engine.renderer, SDL_BLENDMODE_BLEND);117118#if RETRO_SOFTWARE_RENDER119Engine.screenBuffer = SDL_CreateTexture(Engine.renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, SCREEN_XSIZE, SCREEN_YSIZE);120121if (!Engine.screenBuffer) {122PrintLog("ERROR: failed to create screen buffer!\nerror msg: %s", SDL_GetError());123return 0;124}125126Engine.screenBuffer2x =127SDL_CreateTexture(Engine.renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, SCREEN_XSIZE * 2, SCREEN_YSIZE * 2);128129if (!Engine.screenBuffer2x) {130PrintLog("ERROR: failed to create screen buffer HQ!\nerror msg: %s", SDL_GetError());131return 0;132}133#endif134#endif135136if (Engine.borderless) {137SDL_RestoreWindow(Engine.window);138SDL_SetWindowBordered(Engine.window, SDL_FALSE);139}140141SDL_DisplayMode disp;142if (SDL_GetDisplayMode(0, 0, &disp) == 0) {143Engine.screenRefreshRate = disp.refresh_rate;144}145146#endif147148#if RETRO_USING_SDL1149SDL_Init(SDL_INIT_EVERYTHING);150151byte flags = 0;152#if RETRO_USING_OPENGL153flags |= SDL_OPENGL;154#endif155156Engine.windowSurface = SDL_SetVideoMode(SCREEN_XSIZE * Engine.windowScale, SCREEN_YSIZE * Engine.windowScale, 32, SDL_SWSURFACE | flags);157if (!Engine.windowSurface) {158PrintLog("ERROR: failed to create window!\nerror msg: %s", SDL_GetError());159return 0;160}161// Set the window caption162SDL_WM_SetCaption(gameTitle, NULL);163164Engine.screenBuffer =165SDL_CreateRGBSurface(0, SCREEN_XSIZE * Engine.windowScale, SCREEN_YSIZE * Engine.windowScale, 16, 0xF800, 0x7E0, 0x1F, 0x00);166167if (!Engine.screenBuffer) {168PrintLog("ERROR: failed to create screen buffer!\nerror msg: %s", SDL_GetError());169return 0;170}171172/*Engine.screenBuffer2x = SDL_SetVideoMode(SCREEN_XSIZE * 2, SCREEN_YSIZE * 2, 16, SDL_SWSURFACE | flags);173if (!Engine.screenBuffer2x) {174PrintLog("ERROR: failed to create screen buffer HQ!\nerror msg: %s", SDL_GetError());175return 0;176}*/177178if (Engine.startFullScreen) {179Engine.windowSurface =180SDL_SetVideoMode(SCREEN_XSIZE * Engine.windowScale, SCREEN_YSIZE * Engine.windowScale, 16, SDL_SWSURFACE | SDL_FULLSCREEN | flags);181SDL_ShowCursor(SDL_FALSE);182Engine.isFullScreen = true;183}184185// TODO: not supported in 1.2?186if (Engine.borderless) {187// SDL_RestoreWindow(Engine.window);188// SDL_SetWindowBordered(Engine.window, SDL_FALSE);189}190191// SDL_SetWindowPosition(Engine.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);192193Engine.useHQModes = false; // disabled194Engine.borderless = false; // disabled195#endif196197#if RETRO_USING_OPENGL198199// Init GL200Engine.glContext = SDL_GL_CreateContext(Engine.window);201202SDL_GL_SetSwapInterval(Engine.vsync ? 1 : 0);203204#if RETRO_PLATFORM != RETRO_ANDROID && RETRO_PLATFORM != RETRO_OSX205GLenum err = glewInit();206if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) {207PrintLog("glew init error:");208PrintLog((const char *)glewGetErrorString(err));209return false;210}211#endif212213displaySettings.unknown2 = 0;214215glClearColor(0.0, 0.0, 0.0, 1.0);216217glDisable(GL_LIGHTING);218glEnable(GL_TEXTURE_2D);219glDisable(GL_DEPTH_TEST);220glDisable(GL_DITHER);221glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);222glDisable(GL_BLEND);223glEnable(GL_CULL_FACE);224225glMatrixMode(GL_PROJECTION);226glLoadIdentity();227228#if RETRO_PLATFORM == RETRO_ANDROID229Engine.windowScale = 1;230displaySettings.width = SCREEN_XSIZE;231displaySettings.height = SCREEN_YSIZE;232#else233displaySettings.width = SCREEN_XSIZE_CONFIG * Engine.windowScale;234displaySettings.height = SCREEN_YSIZE * Engine.windowScale;235#endif236237textureList[0].id = -1;238SetupViewport();239240ResetRenderStates();241SetupDrawIndexList();242243for (int c = 0; c < 0x10000; ++c) {244int r = (c & 0b1111100000000000) >> 8;245int g = (c & 0b0000011111100000) >> 3;246int b = (c & 0b0000000000011111) << 3;247gfxPalette16to32[c] = (0xFF << 24) | (b << 16) | (g << 8) | (r << 0);248}249250float lightAmbient[4] = { 2.0, 2.0, 2.0, 1.0 };251float lightDiffuse[4] = { 1.0, 1.0, 1.0, 1.0 };252float lightPos[4] = { 0.0, 0.0, 0.0, 1.0 };253254glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);255glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);256glLightfv(GL_LIGHT0, GL_POSITION, lightPos);257glEnable(GL_LIGHT0);258259#if RETRO_PLATFORM == RETRO_ANDROID260Engine.startFullScreen = true;261#endif262#endif263264#if RETRO_PLATFORM != RETRO_ANDROID265SetScreenDimensions(SCREEN_XSIZE_CONFIG * Engine.windowScale, SCREEN_YSIZE * Engine.windowScale);266#else267SetScreenDimensions(SCREEN_XSIZE, SCREEN_YSIZE);268#endif269270#if RETRO_SOFTWARE_RENDER271Engine.frameBuffer = new ushort[GFX_LINESIZE * SCREEN_YSIZE];272Engine.frameBuffer2x = new ushort[GFX_LINESIZE_DOUBLE * (SCREEN_YSIZE * 2)];273memset(Engine.frameBuffer, 0, (GFX_LINESIZE * SCREEN_YSIZE) * sizeof(ushort));274memset(Engine.frameBuffer2x, 0, GFX_LINESIZE_DOUBLE * (SCREEN_YSIZE * 2) * sizeof(ushort));275#endif276Engine.texBuffer = new uint[GFX_LINESIZE * SCREEN_YSIZE];277memset(Engine.texBuffer, 0, (GFX_LINESIZE * SCREEN_YSIZE) * sizeof(uint));278279#endif280281if (Engine.startFullScreen) {282SetFullScreen(true);283}284285OBJECT_BORDER_X2 = SCREEN_XSIZE + 0x80;286// OBJECT_BORDER_Y2 = SCREEN_YSIZE + 0x100;287OBJECT_BORDER_X4 = SCREEN_XSIZE + 0x20;288// OBJECT_BORDER_Y4 = SCREEN_YSIZE + 0x80;289290InitInputDevices();291292return 1;293}294void FlipScreen()295{296#if !RETRO_USE_ORIGINAL_CODE297float dimAmount = 1.0;298if ((!Engine.masterPaused || Engine.frameStep) && !drawStageGFXHQ) {299if (Engine.dimTimer < Engine.dimLimit) {300if (Engine.dimPercent < 1.0) {301Engine.dimPercent += 0.05;302if (Engine.dimPercent > 1.0)303Engine.dimPercent = 1.0;304}305}306else if (Engine.dimPercent > 0.25 && Engine.dimLimit >= 0) {307Engine.dimPercent *= 0.9;308}309310dimAmount = Engine.dimMax * Engine.dimPercent;311}312313#if RETRO_SOFTWARE_RENDER && !RETRO_USING_OPENGL314#if RETRO_USING_SDL2315SDL_Rect destScreenPos_scaled;316SDL_Texture *texTarget = NULL;317318switch (Engine.scalingMode) {319// reset to default if value is invalid.320default: Engine.scalingMode = 0; break;321case 0: break; // nearest322case 1: integerScaling = true; break; // integer scaling323case 2: break; // sharp bilinear324case 3: bilinearScaling = true; break; // regular old bilinear325}326327SDL_GetWindowSize(Engine.window, &Engine.windowXSize, &Engine.windowYSize);328float screenxsize = SCREEN_XSIZE;329float screenysize = SCREEN_YSIZE;330331// check if enhanced scaling is even necessary to be calculated by checking if the screen size is close enough on one axis332// unfortunately it has to be "close enough" because of floating point precision errors. dang it333if (Engine.scalingMode == 2) {334bool cond1 = std::round((Engine.windowXSize / screenxsize) * 24) / 24 == std::floor(Engine.windowXSize / screenxsize);335bool cond2 = std::round((Engine.windowYSize / screenysize) * 24) / 24 == std::floor(Engine.windowYSize / screenysize);336if (cond1 || cond2)337disableEnhancedScaling = true;338}339340// get 2x resolution if HQ is enabled.341if (drawStageGFXHQ) {342screenxsize *= 2;343screenysize *= 2;344}345346if (Engine.scalingMode != 0 && !disableEnhancedScaling) {347// set up integer scaled texture, which is scaled to the largest integer scale of the screen buffer348// before you make a texture that's larger than the window itself. This texture will then be scaled349// up to the actual screen size using linear interpolation. This makes even window/screen scales350// nice and sharp, and uneven scales as sharp as possible without creating wonky pixel scales,351// creating a nice image.352353// get integer scale354float scale = 1;355if (!bilinearScaling) {356scale =357std::fminf(std::floor((float)Engine.windowXSize / (float)SCREEN_XSIZE), std::floor((float)Engine.windowYSize / (float)SCREEN_YSIZE));358}359SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // set interpolation to linear360// create texture that's integer scaled.361texTarget = SDL_CreateTexture(Engine.renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_TARGET, SCREEN_XSIZE * scale, SCREEN_YSIZE * scale);362363// keep aspect364float aspectScale = std::fminf(Engine.windowYSize / screenysize, Engine.windowXSize / screenxsize);365if (integerScaling) {366aspectScale = std::floor(aspectScale);367}368float xoffset = (Engine.windowXSize - (screenxsize * aspectScale)) / 2;369float yoffset = (Engine.windowYSize - (screenysize * aspectScale)) / 2;370destScreenPos_scaled.x = std::round(xoffset);371destScreenPos_scaled.y = std::round(yoffset);372destScreenPos_scaled.w = std::round(screenxsize * aspectScale);373destScreenPos_scaled.h = std::round(screenysize * aspectScale);374// fill the screen with the texture, making lerp work.375SDL_RenderSetLogicalSize(Engine.renderer, Engine.windowXSize, Engine.windowYSize);376}377378int pitch = 0;379SDL_SetRenderTarget(Engine.renderer, texTarget);380381// Clear the screen. This is needed to keep the382// pillarboxes in fullscreen from displaying garbage data.383SDL_RenderClear(Engine.renderer);384385ushort *pixels = NULL;386if (!drawStageGFXHQ) {387SDL_LockTexture(Engine.screenBuffer, NULL, (void **)&pixels, &pitch);388ushort *frameBufferPtr = Engine.frameBuffer;389for (int y = 0; y < SCREEN_YSIZE; ++y) {390memcpy(pixels, frameBufferPtr, SCREEN_XSIZE * sizeof(ushort));391frameBufferPtr += GFX_LINESIZE;392pixels += pitch / sizeof(ushort);393}394// memcpy(pixels, Engine.frameBuffer, pitch * SCREEN_YSIZE); //faster but produces issues with odd numbered screen sizes395SDL_UnlockTexture(Engine.screenBuffer);396397SDL_RenderCopy(Engine.renderer, Engine.screenBuffer, NULL, NULL);398}399else {400int w = 0, h = 0;401SDL_QueryTexture(Engine.screenBuffer2x, NULL, NULL, &w, &h);402SDL_LockTexture(Engine.screenBuffer2x, NULL, (void **)&pixels, &pitch);403404ushort *framebufferPtr = Engine.frameBuffer;405for (int y = 0; y < (SCREEN_YSIZE / 2) + 12; ++y) {406for (int x = 0; x < GFX_LINESIZE; ++x) {407*pixels = *framebufferPtr;408pixels++;409*pixels = *framebufferPtr;410pixels++;411framebufferPtr++;412}413414framebufferPtr -= GFX_LINESIZE;415for (int x = 0; x < GFX_LINESIZE; ++x) {416*pixels = *framebufferPtr;417pixels++;418*pixels = *framebufferPtr;419pixels++;420framebufferPtr++;421}422}423424framebufferPtr = Engine.frameBuffer2x;425for (int y = 0; y < ((SCREEN_YSIZE / 2) - 12) * 2; ++y) {426for (int x = 0; x < GFX_LINESIZE; ++x) {427*pixels = *framebufferPtr;428framebufferPtr++;429pixels++;430431*pixels = *framebufferPtr;432framebufferPtr++;433pixels++;434}435}436SDL_UnlockTexture(Engine.screenBuffer2x);437SDL_RenderCopy(Engine.renderer, Engine.screenBuffer2x, NULL, NULL);438}439440if (Engine.scalingMode != 0 && !disableEnhancedScaling) {441// set render target back to the screen.442SDL_SetRenderTarget(Engine.renderer, NULL);443// clear the screen itself now, for same reason as above444SDL_RenderClear(Engine.renderer);445// copy texture to screen with lerp446SDL_RenderCopy(Engine.renderer, texTarget, NULL, &destScreenPos_scaled);447// Apply dimming448SDL_SetRenderDrawColor(Engine.renderer, 0, 0, 0, 0xFF - (dimAmount * 0xFF));449if (dimAmount < 1.0)450SDL_RenderFillRect(Engine.renderer, NULL);451// finally present it452SDL_RenderPresent(Engine.renderer);453// reset everything just in case454SDL_RenderSetLogicalSize(Engine.renderer, SCREEN_XSIZE, SCREEN_YSIZE);455SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");456// putting some FLEX TAPE� on that memory leak457SDL_DestroyTexture(texTarget);458}459else {460// Apply dimming461SDL_SetRenderDrawColor(Engine.renderer, 0, 0, 0, 0xFF - (dimAmount * 0xFF));462if (dimAmount < 1.0)463SDL_RenderFillRect(Engine.renderer, NULL);464// no change here465SDL_RenderPresent(Engine.renderer);466}467SDL_ShowWindow(Engine.window);468#endif469470#if RETRO_USING_SDL1471ushort *px = (ushort *)Engine.screenBuffer->pixels;472int w = SCREEN_XSIZE * Engine.windowScale;473int h = SCREEN_YSIZE * Engine.windowScale;474475if (Engine.windowScale == 1) {476ushort *frameBufferPtr = Engine.frameBuffer;477for (int y = 0; y < SCREEN_YSIZE; ++y) {478for (int x = 0; x < SCREEN_XSIZE; ++x) {479pixels[x] = frameBufferPtr[x];480}481frameBufferPtr += GFX_LINESIZE;482px += Engine.screenBuffer->pitch / sizeof(ushort);483}484// memcpy(Engine.screenBuffer->pixels, Engine.frameBuffer, Engine.screenBuffer->pitch * SCREEN_YSIZE);485}486else {487// TODO: this better, I really dont know how to use SDL1.2 well lol488int dx = 0, dy = 0;489do {490do {491int x = (int)(dx * (1.0f / Engine.windowScale));492int y = (int)(dy * (1.0f / Engine.windowScale));493494px[dx + (dy * w)] = Engine.frameBuffer[x + (y * GFX_LINESIZE)];495496dx++;497} while (dx < w);498dy++;499dx = 0;500} while (dy < h);501}502503// Apply image to screen504SDL_BlitSurface(Engine.screenBuffer, NULL, Engine.windowSurface, NULL);505506// Update Screen507SDL_Flip(Engine.windowSurface);508#endif509510#endif // !RETRO_SOFTWARE_RENDER511512#endif513}514void ReleaseRenderDevice(bool refresh)515{516if (!refresh) {517ClearMeshData();518ClearTextures(false);519}520521#if !RETRO_USE_ORIGINAL_CODE522#if RETRO_SOFTWARE_RENDER523if (Engine.frameBuffer)524delete[] Engine.frameBuffer;525if (Engine.frameBuffer2x)526delete[] Engine.frameBuffer2x;527#if RETRO_USING_SDL2 && !RETRO_USING_OPENGL528SDL_DestroyTexture(Engine.screenBuffer);529Engine.screenBuffer = NULL;530#endif531if (Engine.texBuffer)532delete[] Engine.texBuffer;533534#if RETRO_USING_SDL1535SDL_FreeSurface(Engine.screenBuffer);536#endif537#endif538539#if RETRO_USING_OPENGL540if (Engine.glContext)541SDL_GL_DeleteContext(Engine.glContext);542#endif543544#if RETRO_USING_SDL2545#if !RETRO_USING_OPENGL546SDL_DestroyRenderer(Engine.renderer);547#endif548SDL_DestroyWindow(Engine.window);549#endif550#endif551}552553void GenerateBlendLookupTable(void)554{555for (int y = 0; y < 0x100; y++) {556for (int x = 0; x < 0x20; x++) {557blendLookupTable[x + (0x20 * y)] = y * x >> 8;558subtractLookupTable[x + (0x20 * y)] = y * (0x1F - x) >> 8;559}560}561562for (int i = 0; i < 0x10000; i++) {563int tintValue = ((i & 0x1F) + ((i & 0x7E0) >> 6) + ((i & 0xF800) >> 11)) / 3 + 6;564tintLookupTable[i] = 0x841 * minVal(tintValue, 0x1F);565}566}567568void ClearScreen(byte index)569{570#if RETRO_SOFTWARE_RENDER571ushort color = activePalette[index];572ushort *framebuffer = Engine.frameBuffer;573int cnt = GFX_LINESIZE * SCREEN_YSIZE;574while (cnt--) {575*framebuffer = color;576++framebuffer;577}578#endif579}580581void SetScreenDimensions(int width, int height)582{583touchWidth = width;584touchHeight = height;585displaySettings.width = width;586displaySettings.height = height;587touchWidthF = width;588displaySettings.unknown1 = 16;589touchHeightF = height;590// displaySettings.maxWidth = 424;591double aspect = (((width >> 16) * 65536.0) + width) / (((height >> 16) * 65536.0) + height);592SCREEN_XSIZE_F = SCREEN_YSIZE * aspect;593SCREEN_CENTERX_F = aspect * SCREEN_CENTERY;594SetPerspectiveMatrix(SCREEN_YSIZE * aspect, SCREEN_YSIZE_F, 0.0, 1000.0);595#if RETRO_USING_OPENGL596glViewport(0, 0, displaySettings.width, displaySettings.height);597#endif598599Engine.useHighResAssets = displaySettings.height > (SCREEN_YSIZE * 2);600int displayWidth = aspect * SCREEN_YSIZE;601// if (val > displaySettings.maxWidth)602// val = displaySettings.maxWidth;603#if !RETRO_USE_ORIGINAL_CODE604SetScreenSize(displayWidth, (displayWidth + 9) & -0x8);605#else606SetScreenSize(displayWidth, (displayWidth + 9) & -0x10);607#endif608609int width2 = 0;610int wBuf = GFX_LINESIZE - 1;611while (wBuf > 0) {612width2++;613wBuf >>= 1;614}615int height2 = 0;616int hBuf = SCREEN_YSIZE - 1;617while (hBuf > 0) {618height2++;619hBuf >>= 1;620}621int texWidth = 1 << width2;622int texHeight = 1 << height2;623624textureList[0].widthN = 1.0f / texWidth;625textureList[0].heightN = 1.0f / texHeight;626627float w = (SCREEN_XSIZE * textureList[0].widthN);628float w2 = (GFX_LINESIZE * textureList[0].widthN);629float h = (SCREEN_YSIZE * textureList[0].heightN);630631retroVertexList[0] = -SCREEN_CENTERX_F;632retroVertexList[1] = SCREEN_CENTERY_F;633retroVertexList[2] = 160.0;634retroVertexList[6] = 0.0;635retroVertexList[7] = 0.0;636637retroVertexList[9] = SCREEN_CENTERX_F;638retroVertexList[10] = SCREEN_CENTERY_F;639retroVertexList[11] = 160.0;640retroVertexList[15] = w;641retroVertexList[16] = 0.0;642643retroVertexList[18] = -SCREEN_CENTERX_F;644retroVertexList[19] = -SCREEN_CENTERY_F;645retroVertexList[20] = 160.0;646retroVertexList[24] = 0.0;647retroVertexList[25] = h;648649retroVertexList[27] = SCREEN_CENTERX_F;650retroVertexList[28] = -SCREEN_CENTERY_F;651retroVertexList[29] = 160.0;652retroVertexList[33] = w;653retroVertexList[34] = h;654655screenBufferVertexList[0] = -1.0;656screenBufferVertexList[1] = 1.0;657screenBufferVertexList[2] = 1.0;658screenBufferVertexList[6] = 0.0;659screenBufferVertexList[7] = h;660661screenBufferVertexList[9] = 1.0;662screenBufferVertexList[10] = 1.0;663screenBufferVertexList[11] = 1.0;664screenBufferVertexList[15] = w2;665screenBufferVertexList[16] = h;666667screenBufferVertexList[18] = -1.0;668screenBufferVertexList[19] = -1.0;669screenBufferVertexList[20] = 1.0;670screenBufferVertexList[24] = 0.0;671screenBufferVertexList[25] = 0.0;672673screenBufferVertexList[27] = 1.0;674screenBufferVertexList[28] = -1.0;675screenBufferVertexList[29] = 1.0;676screenBufferVertexList[33] = w2;677screenBufferVertexList[34] = 0.0;678}679680void SetScreenSize(int width, int lineSize)681{682SCREEN_XSIZE = width;683SCREEN_CENTERX = width / 2;684SCREEN_SCROLL_LEFT = SCREEN_CENTERX - 8;685SCREEN_SCROLL_RIGHT = SCREEN_CENTERX + 8;686OBJECT_BORDER_X2 = width + 0x80;687OBJECT_BORDER_X4 = width + 0x20;688689GFX_LINESIZE = lineSize;690GFX_LINESIZE_MINUSONE = lineSize - 1;691GFX_LINESIZE_DOUBLE = 2 * lineSize;692GFX_FRAMEBUFFERSIZE = SCREEN_YSIZE * lineSize;693GFX_FBUFFERMINUSONE = SCREEN_YSIZE * lineSize - 1;694}695696#if RETRO_SOFTWARE_RENDER697void CopyFrameOverlay2x()698{699ushort *frameBuffer = &Engine.frameBuffer[((SCREEN_YSIZE / 2) + 12) * GFX_LINESIZE];700ushort *frameBuffer2x = Engine.frameBuffer2x;701702for (int y = 0; y < (SCREEN_YSIZE / 2) - 12; ++y) {703for (int x = 0; x < GFX_LINESIZE; ++x) {704if (*frameBuffer == 0xF81F) { // magenta705frameBuffer2x += 2;706}707else {708*frameBuffer2x = *frameBuffer;709frameBuffer2x++;710*frameBuffer2x = *frameBuffer;711frameBuffer2x++;712}713++frameBuffer;714}715716frameBuffer -= GFX_LINESIZE;717for (int x = 0; x < GFX_LINESIZE; ++x) {718if (*frameBuffer == 0xF81F) { // magenta719frameBuffer2x += 2;720}721else {722*frameBuffer2x = *frameBuffer;723frameBuffer2x++;724*frameBuffer2x = *frameBuffer;725frameBuffer2x++;726}727++frameBuffer;728}729}730}731#endif732733void SetupViewport()734{735double aspect = displaySettings.width / (double)displaySettings.height;736SCREEN_XSIZE_F = SCREEN_YSIZE * aspect;737SCREEN_CENTERX_F = aspect * SCREEN_CENTERY;738739#if RETRO_USING_OPENGL740glScalef(320.0f / (SCREEN_YSIZE * aspect), 1.0, 1.0);741#endif742743SetPerspectiveMatrix(90.0, 0.75, 1.0, 5000.0);744745#if RETRO_USING_OPENGL746glViewport(displaySettings.offsetX, 0, displaySettings.width, displaySettings.height);747#endif748int displayWidth = aspect * SCREEN_YSIZE;749#if !RETRO_USE_ORIGINAL_CODE750SetScreenSize(displayWidth, (displayWidth + 9) & -0x8);751#else752SetScreenSize(displayWidth, (displayWidth + 9) & -0x10);753#endif754755Engine.useHighResAssets = displaySettings.height > (SCREEN_YSIZE * 2);756757#if RETRO_USING_OPENGL758glMatrixMode(GL_MODELVIEW);759glLoadIdentity();760#endif761762int width2 = 0;763int wBuf = GFX_LINESIZE - 1;764while (wBuf > 0) {765width2++;766wBuf >>= 1;767}768int height2 = 0;769int hBuf = SCREEN_YSIZE - 1;770while (hBuf > 0) {771height2++;772hBuf >>= 1;773}774int texWidth = 1 << width2;775int texHeight = 1 << height2;776777float w = (SCREEN_XSIZE * textureList[0].widthN);778float w2 = (GFX_LINESIZE * textureList[0].widthN);779float h = (SCREEN_YSIZE * textureList[0].heightN);780781retroVertexList[0] = -SCREEN_CENTERX_F;782retroVertexList[1] = SCREEN_CENTERY_F;783retroVertexList[2] = 160.0;784retroVertexList[6] = 0.0;785retroVertexList[7] = 0.0;786787retroVertexList[9] = SCREEN_CENTERX_F;788retroVertexList[10] = SCREEN_CENTERY_F;789retroVertexList[11] = 160.0;790retroVertexList[15] = w;791retroVertexList[16] = 0.0;792793retroVertexList[18] = -SCREEN_CENTERX_F;794retroVertexList[19] = -SCREEN_CENTERY_F;795retroVertexList[20] = 160.0;796retroVertexList[24] = 0.0;797retroVertexList[25] = h;798799retroVertexList[27] = SCREEN_CENTERX_F;800retroVertexList[28] = -SCREEN_CENTERY_F;801retroVertexList[29] = 160.0;802retroVertexList[33] = w;803retroVertexList[34] = h;804805screenBufferVertexList[0] = -1.0;806screenBufferVertexList[1] = 1.0;807screenBufferVertexList[2] = 1.0;808screenBufferVertexList[6] = 0.0;809screenBufferVertexList[7] = h;810811screenBufferVertexList[9] = 1.0;812screenBufferVertexList[10] = 1.0;813screenBufferVertexList[11] = 1.0;814screenBufferVertexList[15] = w2;815screenBufferVertexList[16] = h;816817screenBufferVertexList[18] = -1.0;818screenBufferVertexList[19] = -1.0;819screenBufferVertexList[20] = 1.0;820screenBufferVertexList[24] = 0.0;821screenBufferVertexList[25] = 0.0;822823screenBufferVertexList[27] = 1.0;824screenBufferVertexList[28] = -1.0;825screenBufferVertexList[29] = 1.0;826screenBufferVertexList[33] = w2;827screenBufferVertexList[34] = 0.0;828829StrCopy(textureList[0].fileName, "RetroBuffer");830textureList[0].width = texWidth;831textureList[0].height = texHeight;832textureList[0].format = TEXFMT_RETROBUFFER;833textureList[0].widthN = 1.0f / texWidth;834textureList[0].heightN = 1.0f / texHeight;835836if (Engine.useHighResAssets) {837#if RETRO_USING_OPENGL838if (framebufferHiRes != -1)839glDeleteFramebuffers(1, &framebufferHiRes);840if (renderbufferHiRes != -1)841glDeleteTextures(1, &renderbufferHiRes);842framebufferHiRes = -1;843renderbufferHiRes = -1;844845glGenFramebuffers(1, &framebufferHiRes);846glBindFramebuffer(GL_FRAMEBUFFER, framebufferHiRes);847glGenTextures(1, &renderbufferHiRes);848glBindTexture(GL_TEXTURE_2D, renderbufferHiRes);849glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Engine.scalingMode ? GL_LINEAR : GL_NEAREST);850glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Engine.scalingMode ? GL_LINEAR : GL_NEAREST);851glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);852glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);853glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texWidth << 1, texHeight << 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);854glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderbufferHiRes, 0);855glBindFramebuffer(GL_FRAMEBUFFER, 0);856glBindTexture(GL_TEXTURE_2D, 0);857#endif858859float w = (((((GFX_LINESIZE >> 16) * 65536.0) + GFX_LINESIZE) + 0.5) * textureList[0].widthN) - 0.001;860float h = (SCREEN_YSIZE * textureList[0].heightN) - 0.001;861screenBufferVertexList[0] = -1.0;862screenBufferVertexList[1] = 1.0;863screenBufferVertexList[2] = 1.0;864screenBufferVertexList[6] = 0.0;865screenBufferVertexList[9] = 1.0;866screenBufferVertexList[10] = 1.0;867screenBufferVertexList[11] = 1.0;868screenBufferVertexList[7] = h;869screenBufferVertexList[16] = h;870screenBufferVertexList[18] = -1.0;871screenBufferVertexList[19] = -1.0;872screenBufferVertexList[20] = 1.0;873screenBufferVertexList[24] = 0.0;874screenBufferVertexList[25] = 0.0;875screenBufferVertexList[27] = 1.0;876screenBufferVertexList[28] = -1.0;877screenBufferVertexList[29] = 1.0;878screenBufferVertexList[15] = w;879screenBufferVertexList[34] = 0.0;880screenBufferVertexList[33] = w;881}882else {883#if RETRO_USING_OPENGL884if (framebufferHiRes != -1)885glDeleteFramebuffers(1, &framebufferHiRes);886if (renderbufferHiRes != -1)887glDeleteTextures(1, &renderbufferHiRes);888glBindFramebuffer(GL_FRAMEBUFFER, 0);889890framebufferHiRes = -1;891renderbufferHiRes = -1;892#endif893}894895bool transfer = false;896#if RETRO_USING_OPENGL897if (textureList[0].id != -1) {898glDeleteTextures(1, &textureList[0].id);899transfer = true;900}901glGenTextures(1, &textureList[0].id);902glBindTexture(GL_TEXTURE_2D, textureList[0].id);903#endif904905convertTo32Bit = true;906#if RETRO_USING_OPENGL907if (displaySettings.height > 720) {908convertTo32Bit = true;909glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);910}911else if (convertTo32Bit)912glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);913else914glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 0);915916glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Engine.scalingMode ? GL_LINEAR : GL_NEAREST);917glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Engine.scalingMode ? GL_LINEAR : GL_NEAREST);918glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);919glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);920glBindTexture(GL_TEXTURE_2D, 0);921#endif922923mixFiltersOnJekyll = Engine.useHighResAssets;924925if (transfer && Engine.frameBuffer)926TransferRetroBuffer();927}928929void SetFullScreen(bool fs)930{931if (fs) {932#if RETRO_USING_SDL1933Engine.windowSurface =934SDL_SetVideoMode(SCREEN_XSIZE * Engine.windowScale, SCREEN_YSIZE * Engine.windowScale, 16, SDL_SWSURFACE | SDL_FULLSCREEN);935SDL_ShowCursor(SDL_FALSE);936#elif RETRO_USING_SDL2937SDL_RestoreWindow(Engine.window);938SDL_SetWindowFullscreen(Engine.window, SDL_WINDOW_FULLSCREEN_DESKTOP);939SDL_ShowCursor(SDL_FALSE);940941#if RETRO_USING_OPENGL942SDL_DisplayMode mode;943SDL_GetDesktopDisplayMode(0, &mode);944945int w = mode.w;946int h = mode.h;947if (mode.h > mode.w) {948w = mode.h;949h = mode.w;950}951952#if RETRO_PLATFORM != RETRO_iOS && RETRO_PLATFORM != RETRO_ANDROID953float aspect = SCREEN_XSIZE_CONFIG / (float)SCREEN_YSIZE;954displaySettings.height = h;955displaySettings.width = aspect * displaySettings.height;956displaySettings.offsetX = abs(w - displaySettings.width) / 2;957if (displaySettings.width > w) {958displaySettings.offsetX = 0;959displaySettings.width = w;960}961962SetupViewport();963#else964displaySettings.height = h;965displaySettings.width = w;966glViewport(0, 0, displaySettings.width, displaySettings.height);967#endif968#endif969#endif970}971else {972#if RETRO_USING_SDL1973Engine.windowSurface = SDL_SetVideoMode(SCREEN_XSIZE * Engine.windowScale, SCREEN_YSIZE * Engine.windowScale, 16, SDL_SWSURFACE);974SDL_ShowCursor(SDL_TRUE);975#elif RETRO_USING_SDL2976SDL_SetWindowFullscreen(Engine.window, false);977SDL_ShowCursor(SDL_TRUE);978SDL_SetWindowSize(Engine.window, SCREEN_XSIZE_CONFIG * Engine.windowScale, SCREEN_YSIZE * Engine.windowScale);979SDL_SetWindowPosition(Engine.window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);980SDL_RestoreWindow(Engine.window);981982displaySettings.width = SCREEN_XSIZE_CONFIG * Engine.windowScale;983displaySettings.height = SCREEN_YSIZE * Engine.windowScale;984displaySettings.offsetX = 0;985SetupViewport();986#endif987}988Engine.isFullScreen = fs;989}990991void DrawObjectList(int Layer)992{993int size = drawListEntries[Layer].listSize;994for (int i = 0; i < size; ++i) {995objectEntityPos = drawListEntries[Layer].entityRefs[i];996int type = objectEntityList[objectEntityPos].type;997if (type) {998if (scriptCode[objectScriptList[type].eventDraw.scriptCodePtr] > 0)999ProcessScript(objectScriptList[type].eventDraw.scriptCodePtr, objectScriptList[type].eventDraw.jumpTablePtr, EVENT_DRAW);1000}1001}1002}1003void DrawStageGFX()1004{1005waterDrawPos = waterLevel - yScrollOffset;10061007#if RETRO_SOFTWARE_RENDER1008if (waterDrawPos < 0)1009waterDrawPos = 0;10101011if (waterDrawPos > SCREEN_YSIZE)1012waterDrawPos = SCREEN_YSIZE;1013#endif10141015if (tLayerMidPoint < 3) {1016DrawObjectList(0);10171018if (activeTileLayers[0] < LAYER_COUNT) {1019switch (stageLayouts[activeTileLayers[0]].type) {1020case LAYER_HSCROLL: DrawHLineScrollLayer(0); break;10211022case LAYER_VSCROLL: DrawVLineScrollLayer(0); break;10231024case LAYER_3DFLOOR:1025#if RETRO_SOFTWARE_RENDER1026drawStageGFXHQ = false;1027#endif1028Draw3DFloorLayer(0);1029break;10301031case LAYER_3DSKY:1032#if RETRO_SOFTWARE_RENDER1033#if !RETRO_USE_ORIGINAL_CODE1034if (Engine.useHQModes)1035#endif1036drawStageGFXHQ = true;10371038Draw3DSkyLayer(0);1039#endif1040break;10411042default: break;1043}1044}10451046DrawObjectList(1);10471048if (activeTileLayers[1] < LAYER_COUNT) {1049switch (stageLayouts[activeTileLayers[1]].type) {1050case LAYER_HSCROLL: DrawHLineScrollLayer(1); break;10511052case LAYER_VSCROLL: DrawVLineScrollLayer(1); break;10531054case LAYER_3DFLOOR:1055#if RETRO_SOFTWARE_RENDER1056drawStageGFXHQ = false;1057#endif1058Draw3DFloorLayer(1);1059break;10601061case LAYER_3DSKY:1062#if RETRO_SOFTWARE_RENDER1063#if !RETRO_USE_ORIGINAL_CODE1064if (Engine.useHQModes)1065#endif1066drawStageGFXHQ = true;10671068Draw3DSkyLayer(1);1069#endif1070break;10711072default: break;1073}1074}10751076DrawObjectList(2);1077DrawObjectList(3);1078DrawObjectList(4);10791080if (activeTileLayers[2] < LAYER_COUNT) {1081switch (stageLayouts[activeTileLayers[2]].type) {1082case LAYER_HSCROLL: DrawHLineScrollLayer(2); break;10831084case LAYER_VSCROLL: DrawVLineScrollLayer(2); break;10851086case LAYER_3DFLOOR:1087#if RETRO_SOFTWARE_RENDER1088drawStageGFXHQ = false;1089#endif1090Draw3DFloorLayer(2);1091break;10921093case LAYER_3DSKY:1094#if RETRO_SOFTWARE_RENDER1095#if !RETRO_USE_ORIGINAL_CODE1096if (Engine.useHQModes)1097#endif1098drawStageGFXHQ = true;10991100Draw3DSkyLayer(2);1101#endif1102break;11031104default: break;1105}1106}1107}1108else if (tLayerMidPoint < 6) {1109DrawObjectList(0);11101111if (activeTileLayers[0] < LAYER_COUNT) {1112switch (stageLayouts[activeTileLayers[0]].type) {1113case LAYER_HSCROLL: DrawHLineScrollLayer(0); break;11141115case LAYER_VSCROLL: DrawVLineScrollLayer(0); break;11161117case LAYER_3DFLOOR:1118#if RETRO_SOFTWARE_RENDER1119drawStageGFXHQ = false;1120#endif1121Draw3DFloorLayer(0);1122break;11231124case LAYER_3DSKY:1125#if RETRO_SOFTWARE_RENDER1126#if !RETRO_USE_ORIGINAL_CODE1127if (Engine.useHQModes)1128#endif1129drawStageGFXHQ = true;11301131Draw3DSkyLayer(0);1132#endif1133break;11341135default: break;1136}1137}11381139DrawObjectList(1);11401141if (activeTileLayers[1] < LAYER_COUNT) {1142switch (stageLayouts[activeTileLayers[1]].type) {1143case LAYER_HSCROLL: DrawHLineScrollLayer(1); break;11441145case LAYER_VSCROLL: DrawVLineScrollLayer(1); break;11461147case LAYER_3DFLOOR:1148#if RETRO_SOFTWARE_RENDER1149drawStageGFXHQ = false;1150#endif1151Draw3DFloorLayer(1);1152break;11531154case LAYER_3DSKY:1155#if RETRO_SOFTWARE_RENDER1156#if !RETRO_USE_ORIGINAL_CODE1157if (Engine.useHQModes)1158#endif1159drawStageGFXHQ = true;11601161Draw3DSkyLayer(1);1162#endif1163break;11641165default: break;1166}1167}11681169DrawObjectList(2);11701171if (activeTileLayers[2] < LAYER_COUNT) {1172switch (stageLayouts[activeTileLayers[2]].type) {1173case LAYER_HSCROLL: DrawHLineScrollLayer(2); break;1174case LAYER_VSCROLL: DrawVLineScrollLayer(2); break;1175case LAYER_3DFLOOR:1176#if RETRO_SOFTWARE_RENDER1177drawStageGFXHQ = false;1178#endif1179Draw3DFloorLayer(2);1180break;1181case LAYER_3DSKY:1182#if RETRO_SOFTWARE_RENDER1183#if !RETRO_USE_ORIGINAL_CODE1184if (Engine.useHQModes)1185#endif1186drawStageGFXHQ = true;11871188Draw3DSkyLayer(2);1189#endif1190break;1191default: break;1192}1193}11941195DrawObjectList(3);1196DrawObjectList(4);1197}11981199if (tLayerMidPoint < 6) {1200if (activeTileLayers[3] < LAYER_COUNT) {1201switch (stageLayouts[activeTileLayers[3]].type) {1202case LAYER_HSCROLL: DrawHLineScrollLayer(3); break;12031204case LAYER_VSCROLL: DrawVLineScrollLayer(3); break;12051206case LAYER_3DFLOOR:1207#if RETRO_SOFTWARE_RENDER1208drawStageGFXHQ = false;1209#endif1210Draw3DFloorLayer(3);1211break;12121213case LAYER_3DSKY:1214#if RETRO_SOFTWARE_RENDER1215#if !RETRO_USE_ORIGINAL_CODE1216if (Engine.useHQModes)1217#endif1218drawStageGFXHQ = true;12191220Draw3DSkyLayer(3);1221#endif1222break;1223default: break;1224}1225}12261227DrawObjectList(5);1228#if RETRO_REV031229#if !RETRO_USE_ORIGINAL_CODE1230// Hacky fix for Tails Object not working properly in special stages on non-Origins bytecode1231if (forceUseScripts || Engine.usingOrigins)1232#endif1233DrawObjectList(7);1234#endif1235DrawObjectList(6);1236}12371238#if !RETRO_USE_ORIGINAL_CODE1239if (drawStageGFXHQ)1240DrawDebugOverlays();1241#endif12421243#if RETRO_SOFTWARE_RENDER1244if (drawStageGFXHQ) {1245CopyFrameOverlay2x();12461247if (fadeMode > 0) {1248DrawRectangle(0, 0, SCREEN_XSIZE, SCREEN_YSIZE, fadeR, fadeG, fadeB, fadeA);1249SetFadeHQ(fadeR, fadeG, fadeB, fadeA);1250}1251}1252else {1253if (fadeMode > 0) {1254DrawRectangle(0, 0, SCREEN_XSIZE, SCREEN_YSIZE, fadeR, fadeG, fadeB, fadeA);1255}1256}1257#endif12581259#if !RETRO_USE_ORIGINAL_CODE1260if (!drawStageGFXHQ)1261DrawDebugOverlays();1262#endif1263}12641265#if !RETRO_USE_ORIGINAL_CODE1266void DrawDebugOverlays()1267{1268if (showHitboxes) {1269for (int i = 0; i < debugHitboxCount; ++i) {1270DebugHitboxInfo *info = &debugHitboxList[i];1271int x = info->xpos + (info->left << 16);1272int y = info->ypos + (info->top << 16);1273int w = abs((info->xpos + (info->right << 16)) - x) >> 16;1274int h = abs((info->ypos + (info->bottom << 16)) - y) >> 16;1275x = (x >> 16) - xScrollOffset;1276y = (y >> 16) - yScrollOffset;12771278switch (info->type) {1279case H_TYPE_TOUCH:1280if (showHitboxes & 1)1281DrawRectangle(x, y, w, h, info->collision ? 0x80 : 0xFF, info->collision ? 0x80 : 0x00, 0x00, 0x60);1282break;12831284case H_TYPE_BOX:1285if (showHitboxes & 1) {1286DrawRectangle(x, y, w, h, 0x00, 0x00, 0xFF, 0x60);1287if (info->collision & 1) // top1288DrawRectangle(x, y, w, 1, 0xFF, 0xFF, 0x00, 0xC0);1289if (info->collision & 8) // bottom1290DrawRectangle(x, y + h, w, 1, 0xFF, 0xFF, 0x00, 0xC0);1291if (info->collision & 2) { // left1292int sy = y;1293int sh = h;1294if (info->collision & 1) {1295sy++;1296sh--;1297}1298if (info->collision & 8)1299sh--;1300DrawRectangle(x, sy, 1, sh, 0xFF, 0xFF, 0x00, 0xC0);1301}1302if (info->collision & 4) { // right1303int sy = y;1304int sh = h;1305if (info->collision & 1) {1306sy++;1307sh--;1308}1309if (info->collision & 8)1310sh--;1311DrawRectangle(x + w, sy, 1, sh, 0xFF, 0xFF, 0x00, 0xC0);1312}1313}1314break;13151316case H_TYPE_PLAT:1317if (showHitboxes & 1) {1318DrawRectangle(x, y, w, h, 0x00, 0xFF, 0x00, 0x60);1319if (info->collision & 1) // top1320DrawRectangle(x, y, w, 1, 0xFF, 0xFF, 0x00, 0xC0);1321if (info->collision & 8) // bottom1322DrawRectangle(x, y + h, w, 1, 0xFF, 0xFF, 0x00, 0xC0);1323}1324break;13251326case H_TYPE_FINGER:1327if (showHitboxes & 2)1328DrawRectangle(x + xScrollOffset, y + yScrollOffset, w, h, 0xF0, 0x00, 0xF0, 0x60);1329break;1330}1331}1332}13331334if (Engine.showPaletteOverlay) {1335for (int p = 0; p < PALETTE_COUNT; ++p) {1336int x = (SCREEN_XSIZE - (0x10 << 3));1337int y = (SCREEN_YSIZE - (0x10 << 2));1338for (int c = 0; c < PALETTE_COLOR_COUNT; ++c) {1339int g = fullPalette32[p][c].g;1340// HQ mode overrides any magenta px, so slightly change the g channel since it has the most bits to make it "not quite magenta"1341if (drawStageGFXHQ && fullPalette32[p][c].r == 0xFF && fullPalette32[p][c].g == 0x00 && fullPalette32[p][c].b == 0xFF)1342g += 8;13431344DrawRectangle(x + ((c & 0xF) << 1) + ((p % (PALETTE_COUNT / 2)) * (2 * 16)),1345y + ((c >> 4) << 1) + ((p / (PALETTE_COUNT / 2)) * (2 * 16)), 2, 2, fullPalette32[p][c].r, g, fullPalette32[p][c].b,13460xFF);1347}1348}1349}1350}1351#endif13521353void DrawHLineScrollLayer(int layerID)1354{1355TileLayer *layer = &stageLayouts[activeTileLayers[layerID]];1356if (!layer->xsize || !layer->ysize)1357return;13581359#if RETRO_SOFTWARE_RENDER1360int screenwidth16 = (GFX_LINESIZE >> 4) - 1;1361int layerwidth = layer->xsize;1362int layerheight = layer->ysize;1363bool aboveMidPoint = layerID >= tLayerMidPoint;13641365byte *lineScroll;1366int *deformationData;1367int *deformationDataW;13681369int yscrollOffset = 0;1370if (activeTileLayers[layerID]) { // BG Layer1371int yScroll = yScrollOffset * layer->parallaxFactor >> 8;1372int fullheight = layerheight << 7;1373layer->scrollPos += layer->scrollSpeed;1374if (layer->scrollPos > fullheight << 16)1375layer->scrollPos -= fullheight << 16;1376yscrollOffset = (yScroll + (layer->scrollPos >> 16)) % fullheight;1377layerheight = fullheight >> 7;1378lineScroll = layer->lineScroll;1379deformationData = &bgDeformationData2[(byte)(yscrollOffset + layer->deformationOffset)];1380deformationDataW = &bgDeformationData3[(byte)(yscrollOffset + waterDrawPos + layer->deformationOffsetW)];1381}1382else { // FG Layer1383lastXSize = layer->xsize;1384yscrollOffset = yScrollOffset;1385lineScroll = layer->lineScroll;1386for (int i = 0; i < PARALLAX_COUNT; ++i) hParallax.linePos[i] = xScrollOffset;1387deformationData = &bgDeformationData0[(byte)(yscrollOffset + layer->deformationOffset)];1388deformationDataW = &bgDeformationData1[(byte)(yscrollOffset + waterDrawPos + layer->deformationOffsetW)];1389}13901391if (layer->type == LAYER_HSCROLL) {1392if (lastXSize != layerwidth) {1393int fullLayerwidth = layerwidth << 7;1394for (int i = 0; i < hParallax.entryCount; ++i) {1395hParallax.linePos[i] = xScrollOffset * hParallax.parallaxFactor[i] >> 8;1396if (hParallax.scrollPos[i] > fullLayerwidth << 16)1397hParallax.scrollPos[i] -= fullLayerwidth << 16;1398if (hParallax.scrollPos[i] < 0)1399hParallax.scrollPos[i] += fullLayerwidth << 16;1400hParallax.linePos[i] += hParallax.scrollPos[i] >> 16;1401hParallax.linePos[i] %= fullLayerwidth;1402}1403}1404int w = -1;1405if (activeTileLayers[layerID])1406w = layerwidth;1407lastXSize = w;1408}14091410ushort *frameBufferPtr = Engine.frameBuffer;1411byte *lineBuffer = gfxLineBuffer;1412int tileYPos = yscrollOffset % (layerheight << 7);1413if (tileYPos < 0)1414tileYPos += layerheight << 7;1415byte *scrollIndex = &lineScroll[tileYPos];1416int tileY16 = tileYPos & 0xF;1417int chunkY = tileYPos >> 7;1418int tileY = (tileYPos & 0x7F) >> 4;14191420// Draw Above Water (if applicable)1421int drawableLines[2] = { waterDrawPos, SCREEN_YSIZE - waterDrawPos };1422for (int i = 0; i < 2; ++i) {1423while (drawableLines[i]--) {1424activePalette = fullPalette[*lineBuffer];1425activePalette32 = fullPalette32[*lineBuffer];1426lineBuffer++;1427int chunkX = hParallax.linePos[*scrollIndex];1428if (i == 0) {1429if (hParallax.deform[*scrollIndex])1430chunkX += *deformationData;1431++deformationData;1432}1433else {1434if (hParallax.deform[*scrollIndex])1435chunkX += *deformationDataW;1436++deformationDataW;1437}1438++scrollIndex;14391440int fullLayerwidth = layerwidth << 7;1441if (chunkX < 0)1442chunkX += fullLayerwidth;1443if (chunkX >= fullLayerwidth)1444chunkX -= fullLayerwidth;14451446int chunkXPos = chunkX >> 7;1447int tilePxXPos = chunkX & 0xF;1448int tileXPxRemain = TILE_SIZE - tilePxXPos;1449int chunk = (layer->tiles[(chunkX >> 7) + (chunkY << 8)] << 6) + ((chunkX & 0x7F) >> 4) + 8 * tileY;1450int tileOffsetY = TILE_SIZE * tileY16;1451int tileOffsetYFlipX = TILE_SIZE * tileY16 + 0xF;1452int tileOffsetYFlipY = TILE_SIZE * (0xF - tileY16);1453int tileOffsetYFlipXY = TILE_SIZE * (0xF - tileY16) + 0xF;1454int lineRemain = GFX_LINESIZE;14551456byte *gfxDataPtr = NULL;1457int tilePxLineCnt = tileXPxRemain;14581459// Draw the first tile to the left1460if (tiles128x128.visualPlane[chunk] == (byte)aboveMidPoint) {1461lineRemain -= tilePxLineCnt;1462switch (tiles128x128.direction[chunk]) {1463case FLIP_NONE:1464gfxDataPtr = &tilesetGFXData[tileOffsetY + tiles128x128.gfxDataPos[chunk] + tilePxXPos];1465while (tilePxLineCnt--) {1466if (*gfxDataPtr > 0)1467*frameBufferPtr = activePalette[*gfxDataPtr];1468++frameBufferPtr;1469++gfxDataPtr;1470}1471break;1472case FLIP_X:14731474gfxDataPtr = &tilesetGFXData[tileOffsetYFlipX + tiles128x128.gfxDataPos[chunk] - tilePxXPos];1475while (tilePxLineCnt--) {1476if (*gfxDataPtr > 0)1477*frameBufferPtr = activePalette[*gfxDataPtr];1478++frameBufferPtr;1479--gfxDataPtr;1480}1481break;14821483case FLIP_Y:1484gfxDataPtr = &tilesetGFXData[tileOffsetYFlipY + tiles128x128.gfxDataPos[chunk] + tilePxXPos];1485while (tilePxLineCnt--) {1486if (*gfxDataPtr > 0)1487*frameBufferPtr = activePalette[*gfxDataPtr];1488++frameBufferPtr;1489++gfxDataPtr;1490}1491break;14921493case FLIP_XY:1494gfxDataPtr = &tilesetGFXData[tileOffsetYFlipXY + tiles128x128.gfxDataPos[chunk] - tilePxXPos];1495while (tilePxLineCnt--) {1496if (*gfxDataPtr > 0)1497*frameBufferPtr = activePalette[*gfxDataPtr];1498++frameBufferPtr;1499--gfxDataPtr;1500}1501break;1502default: break;1503}1504}1505else {1506frameBufferPtr += tilePxLineCnt;1507lineRemain -= tilePxLineCnt;1508}15091510// Draw the bulk of the tiles1511int chunkTileX = ((chunkX & 0x7F) >> 4) + 1;1512int tilesPerLine = screenwidth16;1513while (tilesPerLine--) {1514if (chunkTileX < 8) {1515++chunk;1516}1517else {1518if (++chunkXPos == layerwidth)1519chunkXPos = 0;15201521chunkTileX = 0;1522chunk = (layer->tiles[chunkXPos + (chunkY << 8)] << 6) + 8 * tileY;1523}1524lineRemain -= TILE_SIZE;15251526// Loop Unrolling (faster but messier code)1527if (tiles128x128.visualPlane[chunk] == (byte)aboveMidPoint) {1528switch (tiles128x128.direction[chunk]) {1529case FLIP_NONE:1530gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetY];1531if (*gfxDataPtr > 0)1532*frameBufferPtr = activePalette[*gfxDataPtr];1533++frameBufferPtr;1534++gfxDataPtr;15351536if (*gfxDataPtr > 0)1537*frameBufferPtr = activePalette[*gfxDataPtr];1538++frameBufferPtr;1539++gfxDataPtr;15401541if (*gfxDataPtr > 0)1542*frameBufferPtr = activePalette[*gfxDataPtr];1543++frameBufferPtr;1544++gfxDataPtr;15451546if (*gfxDataPtr > 0)1547*frameBufferPtr = activePalette[*gfxDataPtr];1548++frameBufferPtr;1549++gfxDataPtr;15501551if (*gfxDataPtr > 0)1552*frameBufferPtr = activePalette[*gfxDataPtr];1553++frameBufferPtr;1554++gfxDataPtr;15551556if (*gfxDataPtr > 0)1557*frameBufferPtr = activePalette[*gfxDataPtr];1558++frameBufferPtr;1559++gfxDataPtr;15601561if (*gfxDataPtr > 0)1562*frameBufferPtr = activePalette[*gfxDataPtr];1563++frameBufferPtr;1564++gfxDataPtr;15651566if (*gfxDataPtr > 0)1567*frameBufferPtr = activePalette[*gfxDataPtr];1568++frameBufferPtr;1569++gfxDataPtr;15701571if (*gfxDataPtr > 0)1572*frameBufferPtr = activePalette[*gfxDataPtr];1573++frameBufferPtr;1574++gfxDataPtr;15751576if (*gfxDataPtr > 0)1577*frameBufferPtr = activePalette[*gfxDataPtr];1578++frameBufferPtr;1579++gfxDataPtr;15801581if (*gfxDataPtr > 0)1582*frameBufferPtr = activePalette[*gfxDataPtr];1583++frameBufferPtr;1584++gfxDataPtr;15851586if (*gfxDataPtr > 0)1587*frameBufferPtr = activePalette[*gfxDataPtr];1588++frameBufferPtr;1589++gfxDataPtr;15901591if (*gfxDataPtr > 0)1592*frameBufferPtr = activePalette[*gfxDataPtr];1593++frameBufferPtr;1594++gfxDataPtr;15951596if (*gfxDataPtr > 0)1597*frameBufferPtr = activePalette[*gfxDataPtr];1598++frameBufferPtr;1599++gfxDataPtr;16001601if (*gfxDataPtr > 0)1602*frameBufferPtr = activePalette[*gfxDataPtr];1603++frameBufferPtr;1604++gfxDataPtr;16051606if (*gfxDataPtr > 0)1607*frameBufferPtr = activePalette[*gfxDataPtr];1608++frameBufferPtr;1609break;16101611case FLIP_X:1612gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetYFlipX];1613if (*gfxDataPtr > 0)1614*frameBufferPtr = activePalette[*gfxDataPtr];1615++frameBufferPtr;1616--gfxDataPtr;16171618if (*gfxDataPtr > 0)1619*frameBufferPtr = activePalette[*gfxDataPtr];1620++frameBufferPtr;1621--gfxDataPtr;16221623if (*gfxDataPtr > 0)1624*frameBufferPtr = activePalette[*gfxDataPtr];1625++frameBufferPtr;1626--gfxDataPtr;16271628if (*gfxDataPtr > 0)1629*frameBufferPtr = activePalette[*gfxDataPtr];1630++frameBufferPtr;1631--gfxDataPtr;16321633if (*gfxDataPtr > 0)1634*frameBufferPtr = activePalette[*gfxDataPtr];1635++frameBufferPtr;1636--gfxDataPtr;16371638if (*gfxDataPtr > 0)1639*frameBufferPtr = activePalette[*gfxDataPtr];1640++frameBufferPtr;1641--gfxDataPtr;16421643if (*gfxDataPtr > 0)1644*frameBufferPtr = activePalette[*gfxDataPtr];1645++frameBufferPtr;1646--gfxDataPtr;16471648if (*gfxDataPtr > 0)1649*frameBufferPtr = activePalette[*gfxDataPtr];1650++frameBufferPtr;1651--gfxDataPtr;16521653if (*gfxDataPtr > 0)1654*frameBufferPtr = activePalette[*gfxDataPtr];1655++frameBufferPtr;1656--gfxDataPtr;16571658if (*gfxDataPtr > 0)1659*frameBufferPtr = activePalette[*gfxDataPtr];1660++frameBufferPtr;1661--gfxDataPtr;16621663if (*gfxDataPtr > 0)1664*frameBufferPtr = activePalette[*gfxDataPtr];1665++frameBufferPtr;1666--gfxDataPtr;16671668if (*gfxDataPtr > 0)1669*frameBufferPtr = activePalette[*gfxDataPtr];1670++frameBufferPtr;1671--gfxDataPtr;16721673if (*gfxDataPtr > 0)1674*frameBufferPtr = activePalette[*gfxDataPtr];1675++frameBufferPtr;1676--gfxDataPtr;16771678if (*gfxDataPtr > 0)1679*frameBufferPtr = activePalette[*gfxDataPtr];1680++frameBufferPtr;1681--gfxDataPtr;16821683if (*gfxDataPtr > 0)1684*frameBufferPtr = activePalette[*gfxDataPtr];1685++frameBufferPtr;1686--gfxDataPtr;16871688if (*gfxDataPtr > 0)1689*frameBufferPtr = activePalette[*gfxDataPtr];1690++frameBufferPtr;1691break;16921693case FLIP_Y:1694gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetYFlipY];1695if (*gfxDataPtr > 0)1696*frameBufferPtr = activePalette[*gfxDataPtr];1697++frameBufferPtr;1698++gfxDataPtr;16991700if (*gfxDataPtr > 0)1701*frameBufferPtr = activePalette[*gfxDataPtr];1702++frameBufferPtr;1703++gfxDataPtr;17041705if (*gfxDataPtr > 0)1706*frameBufferPtr = activePalette[*gfxDataPtr];1707++frameBufferPtr;1708++gfxDataPtr;17091710if (*gfxDataPtr > 0)1711*frameBufferPtr = activePalette[*gfxDataPtr];1712++frameBufferPtr;1713++gfxDataPtr;17141715if (*gfxDataPtr > 0)1716*frameBufferPtr = activePalette[*gfxDataPtr];1717++frameBufferPtr;1718++gfxDataPtr;17191720if (*gfxDataPtr > 0)1721*frameBufferPtr = activePalette[*gfxDataPtr];1722++frameBufferPtr;1723++gfxDataPtr;17241725if (*gfxDataPtr > 0)1726*frameBufferPtr = activePalette[*gfxDataPtr];1727++frameBufferPtr;1728++gfxDataPtr;17291730if (*gfxDataPtr > 0)1731*frameBufferPtr = activePalette[*gfxDataPtr];1732++frameBufferPtr;1733++gfxDataPtr;17341735if (*gfxDataPtr > 0)1736*frameBufferPtr = activePalette[*gfxDataPtr];1737++frameBufferPtr;1738++gfxDataPtr;17391740if (*gfxDataPtr > 0)1741*frameBufferPtr = activePalette[*gfxDataPtr];1742++frameBufferPtr;1743++gfxDataPtr;17441745if (*gfxDataPtr > 0)1746*frameBufferPtr = activePalette[*gfxDataPtr];1747++frameBufferPtr;1748++gfxDataPtr;17491750if (*gfxDataPtr > 0)1751*frameBufferPtr = activePalette[*gfxDataPtr];1752++frameBufferPtr;1753++gfxDataPtr;17541755if (*gfxDataPtr > 0)1756*frameBufferPtr = activePalette[*gfxDataPtr];1757++frameBufferPtr;1758++gfxDataPtr;17591760if (*gfxDataPtr > 0)1761*frameBufferPtr = activePalette[*gfxDataPtr];1762++frameBufferPtr;1763++gfxDataPtr;17641765if (*gfxDataPtr > 0)1766*frameBufferPtr = activePalette[*gfxDataPtr];1767++frameBufferPtr;1768++gfxDataPtr;17691770if (*gfxDataPtr > 0)1771*frameBufferPtr = activePalette[*gfxDataPtr];1772++frameBufferPtr;1773break;17741775case FLIP_XY:1776gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetYFlipXY];1777if (*gfxDataPtr > 0)1778*frameBufferPtr = activePalette[*gfxDataPtr];1779++frameBufferPtr;1780--gfxDataPtr;17811782if (*gfxDataPtr > 0)1783*frameBufferPtr = activePalette[*gfxDataPtr];1784++frameBufferPtr;1785--gfxDataPtr;17861787if (*gfxDataPtr > 0)1788*frameBufferPtr = activePalette[*gfxDataPtr];1789++frameBufferPtr;1790--gfxDataPtr;17911792if (*gfxDataPtr > 0)1793*frameBufferPtr = activePalette[*gfxDataPtr];1794++frameBufferPtr;1795--gfxDataPtr;17961797if (*gfxDataPtr > 0)1798*frameBufferPtr = activePalette[*gfxDataPtr];1799++frameBufferPtr;1800--gfxDataPtr;18011802if (*gfxDataPtr > 0)1803*frameBufferPtr = activePalette[*gfxDataPtr];1804++frameBufferPtr;1805--gfxDataPtr;18061807if (*gfxDataPtr > 0)1808*frameBufferPtr = activePalette[*gfxDataPtr];1809++frameBufferPtr;1810--gfxDataPtr;18111812if (*gfxDataPtr > 0)1813*frameBufferPtr = activePalette[*gfxDataPtr];1814++frameBufferPtr;1815--gfxDataPtr;18161817if (*gfxDataPtr > 0)1818*frameBufferPtr = activePalette[*gfxDataPtr];1819++frameBufferPtr;1820--gfxDataPtr;18211822if (*gfxDataPtr > 0)1823*frameBufferPtr = activePalette[*gfxDataPtr];1824++frameBufferPtr;1825--gfxDataPtr;18261827if (*gfxDataPtr > 0)1828*frameBufferPtr = activePalette[*gfxDataPtr];1829++frameBufferPtr;1830--gfxDataPtr;18311832if (*gfxDataPtr > 0)1833*frameBufferPtr = activePalette[*gfxDataPtr];1834++frameBufferPtr;1835--gfxDataPtr;18361837if (*gfxDataPtr > 0)1838*frameBufferPtr = activePalette[*gfxDataPtr];1839++frameBufferPtr;1840--gfxDataPtr;18411842if (*gfxDataPtr > 0)1843*frameBufferPtr = activePalette[*gfxDataPtr];1844++frameBufferPtr;1845--gfxDataPtr;18461847if (*gfxDataPtr > 0)1848*frameBufferPtr = activePalette[*gfxDataPtr];1849++frameBufferPtr;1850--gfxDataPtr;18511852if (*gfxDataPtr > 0)1853*frameBufferPtr = activePalette[*gfxDataPtr];1854++frameBufferPtr;1855break;1856}1857}1858else {1859frameBufferPtr += TILE_SIZE;1860}1861++chunkTileX;1862}18631864// Draw any remaining tiles1865while (lineRemain > 0) {1866if (chunkTileX++ < 8) {1867++chunk;1868}1869else {1870chunkTileX = 0;1871if (++chunkXPos == layerwidth)1872chunkXPos = 0;18731874chunk = (layer->tiles[chunkXPos + (chunkY << 8)] << 6) + 8 * tileY;1875}18761877tilePxLineCnt = lineRemain >= TILE_SIZE ? TILE_SIZE : lineRemain;1878lineRemain -= tilePxLineCnt;1879if (tiles128x128.visualPlane[chunk] == (byte)aboveMidPoint) {1880switch (tiles128x128.direction[chunk]) {1881case FLIP_NONE:1882gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetY];1883while (tilePxLineCnt--) {1884if (*gfxDataPtr > 0)1885*frameBufferPtr = activePalette[*gfxDataPtr];1886++frameBufferPtr;1887++gfxDataPtr;1888}1889break;18901891case FLIP_X:1892gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetYFlipX];1893while (tilePxLineCnt--) {1894if (*gfxDataPtr > 0)1895*frameBufferPtr = activePalette[*gfxDataPtr];1896++frameBufferPtr;1897--gfxDataPtr;1898}1899break;19001901case FLIP_Y:1902gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetYFlipY];1903while (tilePxLineCnt--) {1904if (*gfxDataPtr > 0)1905*frameBufferPtr = activePalette[*gfxDataPtr];1906++frameBufferPtr;1907++gfxDataPtr;1908}1909break;19101911case FLIP_XY:1912gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetYFlipXY];1913while (tilePxLineCnt--) {1914if (*gfxDataPtr > 0)1915*frameBufferPtr = activePalette[*gfxDataPtr];1916++frameBufferPtr;1917--gfxDataPtr;1918}1919break;19201921default: break;1922}1923}1924else {1925frameBufferPtr += tilePxLineCnt;1926}1927}19281929if (++tileY16 >= TILE_SIZE) {1930tileY16 = 0;1931++tileY;1932}19331934if (tileY >= 8) {1935if (++chunkY == layerheight) {1936chunkY = 0;1937scrollIndex -= 0x80 * layerheight;1938}1939tileY = 0;1940}1941}1942}1943#endif1944}1945void DrawVLineScrollLayer(int layerID)1946{1947TileLayer *layer = &stageLayouts[activeTileLayers[layerID]];1948if (!layer->xsize || !layer->ysize)1949return;1950#if RETRO_SOFTWARE_RENDER1951int layerwidth = layer->xsize;1952int layerheight = layer->ysize;1953bool aboveMidPoint = layerID >= tLayerMidPoint;19541955byte *lineScroll;1956int *deformationData;19571958int xscrollOffset = 0;1959if (activeTileLayers[layerID]) { // BG Layer1960int xScroll = xScrollOffset * layer->parallaxFactor >> 8;1961int fullLayerwidth = layerwidth << 7;1962layer->scrollPos += layer->scrollSpeed;1963if (layer->scrollPos > fullLayerwidth << 16)1964layer->scrollPos -= fullLayerwidth << 16;1965xscrollOffset = (xScroll + (layer->scrollPos >> 16)) % fullLayerwidth;1966layerwidth = fullLayerwidth >> 7;1967lineScroll = layer->lineScroll;1968deformationData = &bgDeformationData2[(byte)(xscrollOffset + layer->deformationOffset)];1969}1970else { // FG Layer1971lastYSize = layer->ysize;1972xscrollOffset = xScrollOffset;1973lineScroll = layer->lineScroll;1974vParallax.linePos[0] = yScrollOffset;1975vParallax.deform[0] = true;1976deformationData = &bgDeformationData0[(byte)(xScrollOffset + layer->deformationOffset)];1977}19781979if (layer->type == LAYER_VSCROLL) {1980if (lastYSize != layerheight) {1981int fullLayerheight = layerheight << 7;1982for (int i = 0; i < vParallax.entryCount; ++i) {1983vParallax.linePos[i] = yScrollOffset * vParallax.parallaxFactor[i] >> 8;19841985vParallax.scrollPos[i] += vParallax.scrollPos[i] << 16;1986if (vParallax.scrollPos[i] > fullLayerheight << 16)1987vParallax.scrollPos[i] -= fullLayerheight << 16;19881989vParallax.linePos[i] += vParallax.scrollPos[i] >> 16;1990vParallax.linePos[i] %= fullLayerheight;1991}1992layerheight = fullLayerheight >> 7;1993}1994lastYSize = layerheight;1995}19961997ushort *frameBufferPtr = Engine.frameBuffer;1998activePalette = fullPalette[gfxLineBuffer[0]];1999activePalette32 = fullPalette32[gfxLineBuffer[0]];2000int tileXPos = xscrollOffset % (layerheight << 7);2001if (tileXPos < 0)2002tileXPos += layerheight << 7;2003byte *scrollIndex = &lineScroll[tileXPos];2004int chunkX = tileXPos >> 7;2005int tileX16 = tileXPos & 0xF;2006int tileX = (tileXPos & 0x7F) >> 4;20072008// Draw Above Water (if applicable)2009int drawableLines = SCREEN_XSIZE;2010while (drawableLines--) {2011int chunkY = vParallax.linePos[*scrollIndex];2012if (vParallax.deform[*scrollIndex])2013chunkY += *deformationData;2014++deformationData;2015++scrollIndex;20162017int fullLayerHeight = layerheight << 7;2018if (chunkY < 0)2019chunkY += fullLayerHeight;2020if (chunkY >= fullLayerHeight)2021chunkY -= fullLayerHeight;20222023int chunkYPos = chunkY >> 7;2024int tileY = chunkY & 0xF;2025int tileYPxRemain = TILE_SIZE - tileY;2026int chunk = (layer->tiles[chunkX + (chunkY >> 7 << 8)] << 6) + tileX + 8 * ((chunkY & 0x7F) >> 4);2027int tileOffsetXFlipX = 0xF - tileX16;2028int tileOffsetXFlipY = tileX16 + SCREEN_YSIZE;2029int tileOffsetXFlipXY = 0xFF - tileX16;2030int lineRemain = SCREEN_YSIZE;20312032byte *gfxDataPtr = NULL;2033int tilePxLineCnt = tileYPxRemain;20342035// Draw the first tile to the left2036if (tiles128x128.visualPlane[chunk] == (byte)aboveMidPoint) {2037lineRemain -= tilePxLineCnt;2038switch (tiles128x128.direction[chunk]) {2039case FLIP_NONE:2040gfxDataPtr = &tilesetGFXData[TILE_SIZE * tileY + tileX16 + tiles128x128.gfxDataPos[chunk]];2041while (tilePxLineCnt--) {2042if (*gfxDataPtr > 0)2043*frameBufferPtr = activePalette[*gfxDataPtr];2044frameBufferPtr += GFX_LINESIZE;2045gfxDataPtr += TILE_SIZE;2046}2047break;20482049case FLIP_X:2050gfxDataPtr = &tilesetGFXData[TILE_SIZE * tileY + tileOffsetXFlipX + tiles128x128.gfxDataPos[chunk]];2051while (tilePxLineCnt--) {2052if (*gfxDataPtr > 0)2053*frameBufferPtr = activePalette[*gfxDataPtr];2054frameBufferPtr += GFX_LINESIZE;2055gfxDataPtr += TILE_SIZE;2056}2057break;20582059case FLIP_Y:2060gfxDataPtr = &tilesetGFXData[tileOffsetXFlipY + tiles128x128.gfxDataPos[chunk] - TILE_SIZE * tileY];2061while (tilePxLineCnt--) {2062if (*gfxDataPtr > 0)2063*frameBufferPtr = activePalette[*gfxDataPtr];2064frameBufferPtr += GFX_LINESIZE;2065gfxDataPtr -= TILE_SIZE;2066}2067break;20682069case FLIP_XY:2070gfxDataPtr = &tilesetGFXData[tileOffsetXFlipXY + tiles128x128.gfxDataPos[chunk] - TILE_SIZE * tileY];2071while (tilePxLineCnt--) {2072if (*gfxDataPtr > 0)2073*frameBufferPtr = activePalette[*gfxDataPtr];2074frameBufferPtr += GFX_LINESIZE;2075gfxDataPtr -= TILE_SIZE;2076}2077break;20782079default: break;2080}2081}2082else {2083frameBufferPtr += GFX_LINESIZE * tileYPxRemain;2084lineRemain -= tilePxLineCnt;2085}20862087// Draw the bulk of the tiles2088int chunkTileY = ((chunkY & 0x7F) >> 4) + 1;2089int tilesPerLine = (SCREEN_YSIZE >> 4) - 1;20902091while (tilesPerLine--) {2092if (chunkTileY < 8) {2093chunk += 8;2094}2095else {2096if (++chunkYPos == layerheight)2097chunkYPos = 0;20982099chunkTileY = 0;2100chunk = (layer->tiles[chunkX + (chunkYPos << 8)] << 6) + tileX;2101}2102lineRemain -= TILE_SIZE;21032104// Loop Unrolling (faster but messier code)2105if (tiles128x128.visualPlane[chunk] == (byte)aboveMidPoint) {2106switch (tiles128x128.direction[chunk]) {2107case FLIP_NONE:2108gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileX16];2109if (*gfxDataPtr > 0)2110*frameBufferPtr = activePalette[*gfxDataPtr];2111frameBufferPtr += GFX_LINESIZE;2112gfxDataPtr += TILE_SIZE;21132114if (*gfxDataPtr > 0)2115*frameBufferPtr = activePalette[*gfxDataPtr];2116frameBufferPtr += GFX_LINESIZE;2117gfxDataPtr += TILE_SIZE;21182119if (*gfxDataPtr > 0)2120*frameBufferPtr = activePalette[*gfxDataPtr];2121frameBufferPtr += GFX_LINESIZE;2122gfxDataPtr += TILE_SIZE;21232124if (*gfxDataPtr > 0)2125*frameBufferPtr = activePalette[*gfxDataPtr];2126frameBufferPtr += GFX_LINESIZE;2127gfxDataPtr += TILE_SIZE;21282129if (*gfxDataPtr > 0)2130*frameBufferPtr = activePalette[*gfxDataPtr];2131frameBufferPtr += GFX_LINESIZE;2132gfxDataPtr += TILE_SIZE;21332134if (*gfxDataPtr > 0)2135*frameBufferPtr = activePalette[*gfxDataPtr];2136frameBufferPtr += GFX_LINESIZE;2137gfxDataPtr += TILE_SIZE;21382139if (*gfxDataPtr > 0)2140*frameBufferPtr = activePalette[*gfxDataPtr];2141frameBufferPtr += GFX_LINESIZE;2142gfxDataPtr += TILE_SIZE;21432144if (*gfxDataPtr > 0)2145*frameBufferPtr = activePalette[*gfxDataPtr];2146frameBufferPtr += GFX_LINESIZE;2147gfxDataPtr += TILE_SIZE;21482149if (*gfxDataPtr > 0)2150*frameBufferPtr = activePalette[*gfxDataPtr];2151frameBufferPtr += GFX_LINESIZE;2152gfxDataPtr += TILE_SIZE;21532154if (*gfxDataPtr > 0)2155*frameBufferPtr = activePalette[*gfxDataPtr];2156frameBufferPtr += GFX_LINESIZE;2157gfxDataPtr += TILE_SIZE;21582159if (*gfxDataPtr > 0)2160*frameBufferPtr = activePalette[*gfxDataPtr];2161frameBufferPtr += GFX_LINESIZE;2162gfxDataPtr += TILE_SIZE;21632164if (*gfxDataPtr > 0)2165*frameBufferPtr = activePalette[*gfxDataPtr];2166frameBufferPtr += GFX_LINESIZE;2167gfxDataPtr += TILE_SIZE;21682169if (*gfxDataPtr > 0)2170*frameBufferPtr = activePalette[*gfxDataPtr];2171frameBufferPtr += GFX_LINESIZE;2172gfxDataPtr += TILE_SIZE;21732174if (*gfxDataPtr > 0)2175*frameBufferPtr = activePalette[*gfxDataPtr];2176frameBufferPtr += GFX_LINESIZE;2177gfxDataPtr += TILE_SIZE;21782179if (*gfxDataPtr > 0)2180*frameBufferPtr = activePalette[*gfxDataPtr];2181frameBufferPtr += GFX_LINESIZE;2182gfxDataPtr += TILE_SIZE;21832184if (*gfxDataPtr > 0)2185*frameBufferPtr = activePalette[*gfxDataPtr];2186frameBufferPtr += GFX_LINESIZE;2187break;21882189case FLIP_X:2190gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetXFlipX];2191if (*gfxDataPtr > 0)2192*frameBufferPtr = activePalette[*gfxDataPtr];2193frameBufferPtr += GFX_LINESIZE;2194gfxDataPtr += TILE_SIZE;21952196if (*gfxDataPtr > 0)2197*frameBufferPtr = activePalette[*gfxDataPtr];2198frameBufferPtr += GFX_LINESIZE;2199gfxDataPtr += TILE_SIZE;22002201if (*gfxDataPtr > 0)2202*frameBufferPtr = activePalette[*gfxDataPtr];2203frameBufferPtr += GFX_LINESIZE;2204gfxDataPtr += TILE_SIZE;22052206if (*gfxDataPtr > 0)2207*frameBufferPtr = activePalette[*gfxDataPtr];2208frameBufferPtr += GFX_LINESIZE;2209gfxDataPtr += TILE_SIZE;22102211if (*gfxDataPtr > 0)2212*frameBufferPtr = activePalette[*gfxDataPtr];2213frameBufferPtr += GFX_LINESIZE;2214gfxDataPtr += TILE_SIZE;22152216if (*gfxDataPtr > 0)2217*frameBufferPtr = activePalette[*gfxDataPtr];2218frameBufferPtr += GFX_LINESIZE;2219gfxDataPtr += TILE_SIZE;22202221if (*gfxDataPtr > 0)2222*frameBufferPtr = activePalette[*gfxDataPtr];2223frameBufferPtr += GFX_LINESIZE;2224gfxDataPtr += TILE_SIZE;22252226if (*gfxDataPtr > 0)2227*frameBufferPtr = activePalette[*gfxDataPtr];2228frameBufferPtr += GFX_LINESIZE;2229gfxDataPtr += TILE_SIZE;22302231if (*gfxDataPtr > 0)2232*frameBufferPtr = activePalette[*gfxDataPtr];2233frameBufferPtr += GFX_LINESIZE;2234gfxDataPtr += TILE_SIZE;22352236if (*gfxDataPtr > 0)2237*frameBufferPtr = activePalette[*gfxDataPtr];2238frameBufferPtr += GFX_LINESIZE;2239gfxDataPtr += TILE_SIZE;22402241if (*gfxDataPtr > 0)2242*frameBufferPtr = activePalette[*gfxDataPtr];2243frameBufferPtr += GFX_LINESIZE;2244gfxDataPtr += TILE_SIZE;22452246if (*gfxDataPtr > 0)2247*frameBufferPtr = activePalette[*gfxDataPtr];2248frameBufferPtr += GFX_LINESIZE;2249gfxDataPtr += TILE_SIZE;22502251if (*gfxDataPtr > 0)2252*frameBufferPtr = activePalette[*gfxDataPtr];2253frameBufferPtr += GFX_LINESIZE;2254gfxDataPtr += TILE_SIZE;22552256if (*gfxDataPtr > 0)2257*frameBufferPtr = activePalette[*gfxDataPtr];2258frameBufferPtr += GFX_LINESIZE;2259gfxDataPtr += TILE_SIZE;22602261if (*gfxDataPtr > 0)2262*frameBufferPtr = activePalette[*gfxDataPtr];2263frameBufferPtr += GFX_LINESIZE;2264gfxDataPtr += TILE_SIZE;22652266if (*gfxDataPtr > 0)2267*frameBufferPtr = activePalette[*gfxDataPtr];2268frameBufferPtr += GFX_LINESIZE;2269break;22702271case FLIP_Y:2272gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetXFlipY];2273if (*gfxDataPtr > 0)2274*frameBufferPtr = activePalette[*gfxDataPtr];2275frameBufferPtr += GFX_LINESIZE;2276gfxDataPtr -= TILE_SIZE;22772278if (*gfxDataPtr > 0)2279*frameBufferPtr = activePalette[*gfxDataPtr];2280frameBufferPtr += GFX_LINESIZE;2281gfxDataPtr -= TILE_SIZE;22822283if (*gfxDataPtr > 0)2284*frameBufferPtr = activePalette[*gfxDataPtr];2285frameBufferPtr += GFX_LINESIZE;2286gfxDataPtr -= TILE_SIZE;22872288if (*gfxDataPtr > 0)2289*frameBufferPtr = activePalette[*gfxDataPtr];2290frameBufferPtr += GFX_LINESIZE;2291gfxDataPtr -= TILE_SIZE;22922293if (*gfxDataPtr > 0)2294*frameBufferPtr = activePalette[*gfxDataPtr];2295frameBufferPtr += GFX_LINESIZE;2296gfxDataPtr -= TILE_SIZE;22972298if (*gfxDataPtr > 0)2299*frameBufferPtr = activePalette[*gfxDataPtr];2300frameBufferPtr += GFX_LINESIZE;2301gfxDataPtr -= TILE_SIZE;23022303if (*gfxDataPtr > 0)2304*frameBufferPtr = activePalette[*gfxDataPtr];2305frameBufferPtr += GFX_LINESIZE;2306gfxDataPtr -= TILE_SIZE;23072308if (*gfxDataPtr > 0)2309*frameBufferPtr = activePalette[*gfxDataPtr];2310frameBufferPtr += GFX_LINESIZE;2311gfxDataPtr -= TILE_SIZE;23122313if (*gfxDataPtr > 0)2314*frameBufferPtr = activePalette[*gfxDataPtr];2315frameBufferPtr += GFX_LINESIZE;2316gfxDataPtr -= TILE_SIZE;23172318if (*gfxDataPtr > 0)2319*frameBufferPtr = activePalette[*gfxDataPtr];2320frameBufferPtr += GFX_LINESIZE;2321gfxDataPtr -= TILE_SIZE;23222323if (*gfxDataPtr > 0)2324*frameBufferPtr = activePalette[*gfxDataPtr];2325frameBufferPtr += GFX_LINESIZE;2326gfxDataPtr -= TILE_SIZE;23272328if (*gfxDataPtr > 0)2329*frameBufferPtr = activePalette[*gfxDataPtr];2330frameBufferPtr += GFX_LINESIZE;2331gfxDataPtr -= TILE_SIZE;23322333if (*gfxDataPtr > 0)2334*frameBufferPtr = activePalette[*gfxDataPtr];2335frameBufferPtr += GFX_LINESIZE;2336gfxDataPtr -= TILE_SIZE;23372338if (*gfxDataPtr > 0)2339*frameBufferPtr = activePalette[*gfxDataPtr];2340frameBufferPtr += GFX_LINESIZE;2341gfxDataPtr -= TILE_SIZE;23422343if (*gfxDataPtr > 0)2344*frameBufferPtr = activePalette[*gfxDataPtr];2345frameBufferPtr += GFX_LINESIZE;2346gfxDataPtr -= TILE_SIZE;23472348if (*gfxDataPtr > 0)2349*frameBufferPtr = activePalette[*gfxDataPtr];2350frameBufferPtr += GFX_LINESIZE;2351break;23522353case FLIP_XY:2354gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetXFlipXY];2355if (*gfxDataPtr > 0)2356*frameBufferPtr = activePalette[*gfxDataPtr];2357frameBufferPtr += GFX_LINESIZE;2358gfxDataPtr -= TILE_SIZE;23592360if (*gfxDataPtr > 0)2361*frameBufferPtr = activePalette[*gfxDataPtr];2362frameBufferPtr += GFX_LINESIZE;2363gfxDataPtr -= TILE_SIZE;23642365if (*gfxDataPtr > 0)2366*frameBufferPtr = activePalette[*gfxDataPtr];2367frameBufferPtr += GFX_LINESIZE;2368gfxDataPtr -= TILE_SIZE;23692370if (*gfxDataPtr > 0)2371*frameBufferPtr = activePalette[*gfxDataPtr];2372frameBufferPtr += GFX_LINESIZE;2373gfxDataPtr -= TILE_SIZE;23742375if (*gfxDataPtr > 0)2376*frameBufferPtr = activePalette[*gfxDataPtr];2377frameBufferPtr += GFX_LINESIZE;2378gfxDataPtr -= TILE_SIZE;23792380if (*gfxDataPtr > 0)2381*frameBufferPtr = activePalette[*gfxDataPtr];2382frameBufferPtr += GFX_LINESIZE;2383gfxDataPtr -= TILE_SIZE;23842385if (*gfxDataPtr > 0)2386*frameBufferPtr = activePalette[*gfxDataPtr];2387frameBufferPtr += GFX_LINESIZE;2388gfxDataPtr -= TILE_SIZE;23892390if (*gfxDataPtr > 0)2391*frameBufferPtr = activePalette[*gfxDataPtr];2392frameBufferPtr += GFX_LINESIZE;2393gfxDataPtr -= TILE_SIZE;23942395if (*gfxDataPtr > 0)2396*frameBufferPtr = activePalette[*gfxDataPtr];2397frameBufferPtr += GFX_LINESIZE;2398gfxDataPtr -= TILE_SIZE;23992400if (*gfxDataPtr > 0)2401*frameBufferPtr = activePalette[*gfxDataPtr];2402frameBufferPtr += GFX_LINESIZE;2403gfxDataPtr -= TILE_SIZE;24042405if (*gfxDataPtr > 0)2406*frameBufferPtr = activePalette[*gfxDataPtr];2407frameBufferPtr += GFX_LINESIZE;2408gfxDataPtr -= TILE_SIZE;24092410if (*gfxDataPtr > 0)2411*frameBufferPtr = activePalette[*gfxDataPtr];2412frameBufferPtr += GFX_LINESIZE;2413gfxDataPtr -= TILE_SIZE;24142415if (*gfxDataPtr > 0)2416*frameBufferPtr = activePalette[*gfxDataPtr];2417frameBufferPtr += GFX_LINESIZE;2418gfxDataPtr -= TILE_SIZE;24192420if (*gfxDataPtr > 0)2421*frameBufferPtr = activePalette[*gfxDataPtr];2422frameBufferPtr += GFX_LINESIZE;2423gfxDataPtr -= TILE_SIZE;24242425if (*gfxDataPtr > 0)2426*frameBufferPtr = activePalette[*gfxDataPtr];2427frameBufferPtr += GFX_LINESIZE;2428gfxDataPtr -= TILE_SIZE;24292430if (*gfxDataPtr > 0)2431*frameBufferPtr = activePalette[*gfxDataPtr];2432frameBufferPtr += GFX_LINESIZE;2433break;2434}2435}2436else {2437frameBufferPtr += GFX_LINESIZE * TILE_SIZE;2438}2439++chunkTileY;2440}24412442// Draw any remaining tiles2443while (lineRemain > 0) {2444if (chunkTileY < 8) {2445chunk += 8;2446}2447else {2448if (++chunkYPos == layerheight)2449chunkYPos = 0;24502451chunkTileY = 0;2452chunk = (layer->tiles[chunkX + (chunkYPos << 8)] << 6) + tileX;2453}24542455tilePxLineCnt = lineRemain >= TILE_SIZE ? TILE_SIZE : lineRemain;2456lineRemain -= tilePxLineCnt;24572458if (tiles128x128.visualPlane[chunk] == (byte)aboveMidPoint) {2459switch (tiles128x128.direction[chunk]) {2460case FLIP_NONE:2461gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileX16];2462while (tilePxLineCnt--) {2463if (*gfxDataPtr > 0)2464*frameBufferPtr = activePalette[*gfxDataPtr];2465frameBufferPtr += GFX_LINESIZE;2466gfxDataPtr += TILE_SIZE;2467}2468break;24692470case FLIP_X:2471gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetXFlipX];2472while (tilePxLineCnt--) {2473if (*gfxDataPtr > 0)2474*frameBufferPtr = activePalette[*gfxDataPtr];2475frameBufferPtr += GFX_LINESIZE;2476gfxDataPtr += TILE_SIZE;2477}2478break;24792480case FLIP_Y:2481gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetXFlipY];2482while (tilePxLineCnt--) {2483if (*gfxDataPtr > 0)2484*frameBufferPtr = activePalette[*gfxDataPtr];2485frameBufferPtr += GFX_LINESIZE;2486gfxDataPtr -= TILE_SIZE;2487}2488break;24892490case FLIP_XY:2491gfxDataPtr = &tilesetGFXData[tiles128x128.gfxDataPos[chunk] + tileOffsetXFlipXY];2492while (tilePxLineCnt--) {2493if (*gfxDataPtr > 0)2494*frameBufferPtr = activePalette[*gfxDataPtr];2495frameBufferPtr += GFX_LINESIZE;2496gfxDataPtr -= TILE_SIZE;2497}2498break;24992500default: break;2501}2502}2503else {2504frameBufferPtr += GFX_LINESIZE * tilePxLineCnt;2505}2506chunkTileY++;2507}25082509if (++tileX16 >= TILE_SIZE) {2510tileX16 = 0;2511++tileX;2512}25132514if (tileX >= 8) {2515if (++chunkX == layerwidth) {2516chunkX = 0;2517scrollIndex -= 0x80 * layerwidth;2518}2519tileX = 0;2520}25212522frameBufferPtr -= GFX_FBUFFERMINUSONE;2523}2524#endif2525}2526void Draw3DFloorLayer(int layerID)2527{2528TileLayer *layer = &stageLayouts[activeTileLayers[layerID]];2529if (!layer->xsize || !layer->ysize)2530return;25312532#if RETRO_SOFTWARE_RENDER2533int layerWidth = layer->xsize << 7;2534int layerHeight = layer->ysize << 7;2535int layerYPos = layer->ypos;2536int layerZPos = layer->zpos;2537int sinValue = sinM7LookupTable[layer->angle];2538int cosValue = cosM7LookupTable[layer->angle];2539byte *gfxLineBufferPtr = &gfxLineBuffer[(SCREEN_YSIZE / 2) + 12];2540ushort *frameBufferPtr = &Engine.frameBuffer[((SCREEN_YSIZE / 2) + 12) * GFX_LINESIZE];2541int layerXPos = layer->xpos >> 4;2542int ZBuffer = layerZPos >> 4;2543for (int i = 4; i < 112; ++i) {2544if (!(i & 1)) {2545activePalette = fullPalette[*gfxLineBufferPtr];2546activePalette32 = fullPalette32[*gfxLineBufferPtr];2547gfxLineBufferPtr++;2548}2549int XBuffer = layerYPos / (i << 9) * -cosValue >> 8;2550int YBuffer = sinValue * (layerYPos / (i << 9)) >> 8;2551int XPos = layerXPos + (3 * sinValue * (layerYPos / (i << 9)) >> 2) - XBuffer * SCREEN_CENTERX;2552int YPos = ZBuffer + (3 * cosValue * (layerYPos / (i << 9)) >> 2) - YBuffer * SCREEN_CENTERX;2553int lineBuffer = 0;2554while (lineBuffer < GFX_LINESIZE) {2555int tileX = XPos >> 12;2556int tileY = YPos >> 12;2557if (tileX > -1 && tileX < layerWidth && tileY > -1 && tileY < layerHeight) {2558int chunk = tile3DFloorBuffer[(YPos >> 16 << 8) + (XPos >> 16)];2559byte *tilePixel = &tilesetGFXData[tiles128x128.gfxDataPos[chunk]];2560switch (tiles128x128.direction[chunk]) {2561case FLIP_NONE: tilePixel += 16 * (tileY & 0xF) + (tileX & 0xF); break;2562case FLIP_X: tilePixel += 16 * (tileY & 0xF) + 15 - (tileX & 0xF); break;2563case FLIP_Y: tilePixel += (tileX & 0xF) + SCREEN_YSIZE - 16 * (tileY & 0xF); break;2564case FLIP_XY: tilePixel += 15 - (tileX & 0xF) + SCREEN_YSIZE - 16 * (tileY & 0xF); break;2565default: break;2566}25672568if (*tilePixel > 0)2569*frameBufferPtr = activePalette[*tilePixel];2570}2571++frameBufferPtr;2572++lineBuffer;2573XPos += XBuffer;2574YPos += YBuffer;2575}2576}2577#endif2578}2579void Draw3DSkyLayer(int layerID)2580{2581TileLayer *layer = &stageLayouts[activeTileLayers[layerID]];2582if (!layer->xsize || !layer->ysize)2583return;25842585#if RETRO_SOFTWARE_RENDER2586int layerWidth = layer->xsize << 7;2587int layerHeight = layer->ysize << 7;2588int layerYPos = layer->ypos;2589int sinValue = sinM7LookupTable[layer->angle & 0x1FF];2590int cosValue = cosM7LookupTable[layer->angle & 0x1FF];2591ushort *frameBufferPtr = &Engine.frameBuffer[((SCREEN_YSIZE / 2) + 12) * GFX_LINESIZE];2592ushort *bufferPtr = Engine.frameBuffer2x;2593if (!drawStageGFXHQ)2594bufferPtr = &Engine.frameBuffer[((SCREEN_YSIZE / 2) + 12) * GFX_LINESIZE];2595byte *gfxLineBufferPtr = &gfxLineBuffer[((SCREEN_YSIZE / 2) + 12)];2596int layerXPos = layer->xpos >> 4;2597int layerZPos = layer->zpos >> 4;2598for (int i = TILE_SIZE / 2; i < SCREEN_YSIZE - TILE_SIZE; ++i) {2599if (!(i & 1)) {2600activePalette = fullPalette[*gfxLineBufferPtr];2601activePalette32 = fullPalette32[*gfxLineBufferPtr];2602gfxLineBufferPtr++;2603}2604int xBuffer = layerYPos / (i << 8) * -cosValue >> 9;2605int yBuffer = sinValue * (layerYPos / (i << 8)) >> 9;2606int XPos = layerXPos + (3 * sinValue * (layerYPos / (i << 8)) >> 2) - xBuffer * GFX_LINESIZE;2607int YPos = layerZPos + (3 * cosValue * (layerYPos / (i << 8)) >> 2) - yBuffer * GFX_LINESIZE;2608int lineBuffer = 0;2609while (lineBuffer < GFX_LINESIZE * 2) {2610int tileX = XPos >> 12;2611int tileY = YPos >> 12;2612if (tileX > -1 && tileX < layerWidth && tileY > -1 && tileY < layerHeight) {2613int chunk = tile3DFloorBuffer[(YPos >> 16 << 8) + (XPos >> 16)];2614byte *tilePixel = &tilesetGFXData[tiles128x128.gfxDataPos[chunk]];2615switch (tiles128x128.direction[chunk]) {2616case FLIP_NONE: tilePixel += TILE_SIZE * (tileY & 0xF) + (tileX & 0xF); break;2617case FLIP_X: tilePixel += TILE_SIZE * (tileY & 0xF) + 0xF - (tileX & 0xF); break;2618case FLIP_Y: tilePixel += (tileX & 0xF) + SCREEN_YSIZE - TILE_SIZE * (tileY & 0xF); break;2619case FLIP_XY: tilePixel += 0xF - (tileX & 0xF) + SCREEN_YSIZE - TILE_SIZE * (tileY & 0xF); break;2620default: break;2621}26222623if (*tilePixel > 0)2624*bufferPtr = activePalette[*tilePixel];2625else if (drawStageGFXHQ)2626*bufferPtr = *frameBufferPtr;2627}2628else if (drawStageGFXHQ) {2629*bufferPtr = *frameBufferPtr;2630}26312632if (lineBuffer & 1)2633++frameBufferPtr;26342635if (drawStageGFXHQ)2636bufferPtr++;2637else if (lineBuffer & 1)2638++bufferPtr;26392640lineBuffer++;2641XPos += xBuffer;2642YPos += yBuffer;2643}26442645if (!(i & 1))2646frameBufferPtr -= GFX_LINESIZE;26472648if (!(i & 1) && !drawStageGFXHQ)2649bufferPtr -= GFX_LINESIZE;2650}26512652if (drawStageGFXHQ) {2653frameBufferPtr = &Engine.frameBuffer[((SCREEN_YSIZE / 2) + 12) * GFX_LINESIZE];2654int cnt = ((SCREEN_YSIZE / 2) - 12) * GFX_LINESIZE;2655while (cnt--) *frameBufferPtr++ = 0xF81F; // Magenta2656}2657#endif2658}26592660void DrawRectangle(int XPos, int YPos, int width, int height, int R, int G, int B, int A)2661{2662if (A > 0xFF)2663A = 0xFF;2664#if RETRO_SOFTWARE_RENDER2665if (width + XPos > GFX_LINESIZE)2666width = GFX_LINESIZE - XPos;2667if (XPos < 0) {2668width += XPos;2669XPos = 0;2670}26712672if (height + YPos > SCREEN_YSIZE)2673height = SCREEN_YSIZE - YPos;2674if (YPos < 0) {2675height += YPos;2676YPos = 0;2677}2678if (width <= 0 || height <= 0 || A <= 0)2679return;2680int pitch = GFX_LINESIZE - width;2681ushort *frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];2682ushort clr = PACK_RGB888(R, G, B);2683if (A == 0xFF) {2684int h = height;2685while (h--) {2686int w = width;2687while (w--) {2688*frameBufferPtr = clr;2689++frameBufferPtr;2690}2691frameBufferPtr += pitch;2692}2693}2694else {2695ushort *fbufferBlend = &blendLookupTable[0x20 * (0xFF - A)];2696ushort *pixelBlend = &blendLookupTable[0x20 * A];26972698int h = height;2699while (h--) {2700int w = width;2701while (w--) {2702int R = (fbufferBlend[(*frameBufferPtr & 0xF800) >> 11] + pixelBlend[(clr & 0xF800) >> 11]) << 11;2703int G = (fbufferBlend[(*frameBufferPtr & 0x7E0) >> 6] + pixelBlend[(clr & 0x7E0) >> 6]) << 6;2704int B = fbufferBlend[*frameBufferPtr & 0x1F] + pixelBlend[clr & 0x1F];27052706*frameBufferPtr = R | G | B;2707++frameBufferPtr;2708}2709frameBufferPtr += pitch;2710}2711}2712#endif2713}27142715void SetFadeHQ(int R, int G, int B, int A)2716{2717#if RETRO_SOFTWARE_RENDER2718if (A <= 0)2719return;2720if (A > 0xFF)2721A = 0xFF;2722int pitch = GFX_LINESIZE * 2;2723ushort *frameBufferPtr = Engine.frameBuffer2x;2724ushort clr = PACK_RGB888(R, G, B);2725if (A == 0xFF) {2726int h = SCREEN_YSIZE;2727while (h--) {2728int w = pitch;2729while (w--) {2730*frameBufferPtr = clr;2731++frameBufferPtr;2732}2733}2734}2735else {2736ushort *fbufferBlend = &blendLookupTable[0x20 * (0xFF - A)];2737ushort *pixelBlend = &blendLookupTable[0x20 * A];27382739int h = SCREEN_YSIZE;2740while (h--) {2741int w = pitch;2742while (w--) {2743int R = (fbufferBlend[(*frameBufferPtr & 0xF800) >> 11] + pixelBlend[(clr & 0xF800) >> 11]) << 11;2744int G = (fbufferBlend[(*frameBufferPtr & 0x7E0) >> 6] + pixelBlend[(clr & 0x7E0) >> 6]) << 6;2745int B = fbufferBlend[*frameBufferPtr & 0x1F] + pixelBlend[clr & 0x1F];27462747*frameBufferPtr = R | G | B;2748++frameBufferPtr;2749}2750}2751}2752#endif2753}27542755void DrawTintRectangle(int XPos, int YPos, int width, int height)2756{2757#if RETRO_SOFTWARE_RENDER2758if (width + XPos > GFX_LINESIZE)2759width = GFX_LINESIZE - XPos;2760if (XPos < 0) {2761width += XPos;2762XPos = 0;2763}27642765if (height + YPos > SCREEN_YSIZE)2766height = SCREEN_YSIZE - YPos;2767if (YPos < 0) {2768height += YPos;2769YPos = 0;2770}27712772if (width < 0 || height < 0)2773return;27742775int yOffset = GFX_LINESIZE - width;2776for (ushort *frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];; frameBufferPtr += yOffset) {2777height--;2778if (height < 0)2779break;2780int w = width;2781while (w--) {2782*frameBufferPtr = tintLookupTable[*frameBufferPtr];2783++frameBufferPtr;2784}2785}2786#endif2787}2788void DrawScaledTintMask(int direction, int XPos, int YPos, int pivotX, int pivotY, int scaleX, int scaleY, int width, int height, int sprX, int sprY,2789int sheetID)2790{2791#if RETRO_SOFTWARE_RENDER2792int roundedYPos = 0;2793int roundedXPos = 0;2794int truescaleX = 4 * scaleX;2795int truescaleY = 4 * scaleY;2796int widthM1 = width - 1;2797int trueXPos = XPos - (truescaleX * pivotX >> 11);2798width = truescaleX * width >> 11;2799int trueYPos = YPos - (truescaleY * pivotY >> 11);2800height = truescaleY * height >> 11;2801int finalscaleX = (signed int)(float)((float)(2048.0 / (float)truescaleX) * 2048.0);2802int finalscaleY = (signed int)(float)((float)(2048.0 / (float)truescaleY) * 2048.0);2803if (width + trueXPos > GFX_LINESIZE) {2804width = GFX_LINESIZE - trueXPos;2805}28062807if (direction) {2808if (trueXPos < 0) {2809widthM1 -= trueXPos * -finalscaleX >> 11;2810roundedXPos = (ushort)trueXPos * -(short)finalscaleX & 0x7FF;2811width += trueXPos;2812trueXPos = 0;2813}2814}2815else if (trueXPos < 0) {2816sprX += trueXPos * -finalscaleX >> 11;2817roundedXPos = (ushort)trueXPos * -(short)finalscaleX & 0x7FF;2818width += trueXPos;2819trueXPos = 0;2820}28212822if (height + trueYPos > SCREEN_YSIZE) {2823height = SCREEN_YSIZE - trueYPos;2824}2825if (trueYPos < 0) {2826sprY += trueYPos * -finalscaleY >> 11;2827roundedYPos = (ushort)trueYPos * -(short)finalscaleY & 0x7FF;2828height += trueYPos;2829trueYPos = 0;2830}28312832if (width <= 0 || height <= 0)2833return;28342835GFXSurface *surface = &gfxSurface[sheetID];2836int pitch = GFX_LINESIZE - width;2837int gfxwidth = surface->width;2838// byte *lineBuffer = &gfxLineBuffer[trueYPos];2839byte *gfxData = &graphicData[sprX + surface->width * sprY + surface->dataPosition];2840ushort *frameBufferPtr = &Engine.frameBuffer[trueXPos + GFX_LINESIZE * trueYPos];2841if (direction == FLIP_X) {2842byte *gfxDataPtr = &gfxData[widthM1];2843int gfxPitch = 0;2844while (height--) {2845int roundXPos = roundedXPos;2846int w = width;2847while (w--) {2848if (*gfxDataPtr > 0)2849*frameBufferPtr = tintLookupTable[*frameBufferPtr];2850int offsetX = finalscaleX + roundXPos;2851gfxDataPtr -= offsetX >> 11;2852gfxPitch += offsetX >> 11;2853roundXPos = offsetX & 0x7FF;2854++frameBufferPtr;2855}2856frameBufferPtr += pitch;2857int offsetY = finalscaleY + roundedYPos;2858gfxDataPtr += gfxPitch + (offsetY >> 11) * gfxwidth;2859roundedYPos = offsetY & 0x7FF;2860gfxPitch = 0;2861}2862}2863else {2864int gfxPitch = 0;2865int h = height;2866while (h--) {2867int roundXPos = roundedXPos;2868int w = width;2869while (w--) {2870if (*gfxData > 0)2871*frameBufferPtr = tintLookupTable[*frameBufferPtr];2872int offsetX = finalscaleX + roundXPos;2873gfxData += offsetX >> 11;2874gfxPitch += offsetX >> 11;2875roundXPos = offsetX & 0x7FF;2876++frameBufferPtr;2877}2878frameBufferPtr += pitch;2879int offsetY = finalscaleY + roundedYPos;2880gfxData += (offsetY >> 11) * gfxwidth - gfxPitch;2881roundedYPos = offsetY & 0x7FF;2882gfxPitch = 0;2883}2884}2885#endif2886}28872888void DrawSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int sheetID)2889{2890#if RETRO_SOFTWARE_RENDER2891if (width + XPos > GFX_LINESIZE)2892width = GFX_LINESIZE - XPos;2893if (XPos < 0) {2894sprX -= XPos;2895width += XPos;2896XPos = 0;2897}2898if (height + YPos > SCREEN_YSIZE)2899height = SCREEN_YSIZE - YPos;2900if (YPos < 0) {2901sprY -= YPos;2902height += YPos;2903YPos = 0;2904}2905if (width <= 0 || height <= 0)2906return;29072908GFXSurface *surface = &gfxSurface[sheetID];2909int pitch = GFX_LINESIZE - width;2910int gfxPitch = surface->width - width;2911byte *lineBuffer = &gfxLineBuffer[YPos];2912byte *gfxDataPtr = &graphicData[sprX + surface->width * sprY + surface->dataPosition];2913ushort *frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];2914while (height--) {2915activePalette = fullPalette[*lineBuffer];2916activePalette32 = fullPalette32[*lineBuffer];2917lineBuffer++;2918int w = width;2919while (w--) {2920if (*gfxDataPtr > 0)2921*frameBufferPtr = activePalette[*gfxDataPtr];2922++gfxDataPtr;2923++frameBufferPtr;2924}2925frameBufferPtr += pitch;2926gfxDataPtr += gfxPitch;2927}2928#endif2929}29302931#if RETRO_REV002932void DrawSpriteClipped(int XPos, int YPos, int width, int height, int sprX, int sprY, int sheetID, int clipY)2933{2934if (width + XPos > GFX_LINESIZE)2935width = GFX_LINESIZE - XPos;2936if (XPos < 0) {2937sprX -= XPos;2938width += XPos;2939XPos = 0;2940}2941if (height + YPos > clipY)2942height = clipY - YPos;2943if (YPos < 0) {2944sprY -= YPos;2945height += YPos;2946YPos = 0;2947}2948if (width <= 0 || height <= 0)2949return;29502951GFXSurface *surface = &gfxSurface[sheetID];2952int pitch = GFX_LINESIZE - width;2953int gfxPitch = surface->width - width;2954byte *lineBuffer = &gfxLineBuffer[YPos];2955byte *gfxDataPtr = &graphicData[sprX + surface->width * sprY + surface->dataPosition];2956ushort *frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];2957while (height--) {2958activePalette = fullPalette[*lineBuffer];2959activePalette32 = fullPalette32[*lineBuffer];2960lineBuffer++;2961int w = width;2962while (w--) {2963if (*gfxDataPtr > 0)2964*frameBufferPtr = activePalette[*gfxDataPtr];2965++gfxDataPtr;2966++frameBufferPtr;2967}2968frameBufferPtr += pitch;2969gfxDataPtr += gfxPitch;2970}2971}2972#endif29732974void DrawSpriteFlipped(int XPos, int YPos, int width, int height, int sprX, int sprY, int direction, int sheetID)2975{2976#if RETRO_SOFTWARE_RENDER2977int widthFlip = width;2978int heightFlip = height;29792980if (width + XPos > GFX_LINESIZE) {2981width = GFX_LINESIZE - XPos;2982}2983if (XPos < 0) {2984sprX -= XPos;2985width += XPos;2986widthFlip += XPos + XPos;2987XPos = 0;2988}2989if (height + YPos > SCREEN_YSIZE) {2990height = SCREEN_YSIZE - YPos;2991}2992if (YPos < 0) {2993sprY -= YPos;2994height += YPos;2995heightFlip += YPos + YPos;2996YPos = 0;2997}2998if (width <= 0 || height <= 0)2999return;30003001GFXSurface *surface = &gfxSurface[sheetID];3002int pitch;3003int gfxPitch;3004byte *lineBuffer;3005byte *gfxData;3006ushort *frameBufferPtr;3007switch (direction) {3008case FLIP_NONE:3009pitch = GFX_LINESIZE - width;3010gfxPitch = surface->width - width;3011lineBuffer = &gfxLineBuffer[YPos];3012gfxData = &graphicData[sprX + surface->width * sprY + surface->dataPosition];3013frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];30143015while (height--) {3016activePalette = fullPalette[*lineBuffer];3017activePalette32 = fullPalette32[*lineBuffer];3018lineBuffer++;3019int w = width;3020while (w--) {3021if (*gfxData > 0)3022*frameBufferPtr = activePalette[*gfxData];3023++gfxData;3024++frameBufferPtr;3025}3026frameBufferPtr += pitch;3027gfxData += gfxPitch;3028}3029break;3030case FLIP_X:3031pitch = GFX_LINESIZE - width;3032gfxPitch = width + surface->width;3033lineBuffer = &gfxLineBuffer[YPos];3034gfxData = &graphicData[widthFlip - 1 + sprX + surface->width * sprY + surface->dataPosition];3035frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];3036while (height--) {3037activePalette = fullPalette[*lineBuffer];3038activePalette32 = fullPalette32[*lineBuffer];3039lineBuffer++;3040int w = width;3041while (w--) {3042if (*gfxData > 0)3043*frameBufferPtr = activePalette[*gfxData];3044--gfxData;3045++frameBufferPtr;3046}3047frameBufferPtr += pitch;3048gfxData += gfxPitch;3049}3050break;3051case FLIP_Y:3052pitch = GFX_LINESIZE - width;3053gfxPitch = width + surface->width;3054lineBuffer = &gfxLineBuffer[YPos];3055gfxData = &graphicData[sprX + surface->width * (sprY + heightFlip - 1) + surface->dataPosition];3056frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];3057while (height--) {3058activePalette = fullPalette[*lineBuffer];3059activePalette32 = fullPalette32[*lineBuffer];3060lineBuffer++;3061int w = width;3062while (w--) {3063if (*gfxData > 0)3064*frameBufferPtr = activePalette[*gfxData];3065++gfxData;3066++frameBufferPtr;3067}3068frameBufferPtr += pitch;3069gfxData -= gfxPitch;3070}3071break;3072case FLIP_XY:3073pitch = GFX_LINESIZE - width;3074gfxPitch = surface->width - width;3075lineBuffer = &gfxLineBuffer[YPos];3076gfxData = &graphicData[widthFlip - 1 + sprX + surface->width * (sprY + heightFlip - 1) + surface->dataPosition];3077frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];3078while (height--) {3079activePalette = fullPalette[*lineBuffer];3080activePalette32 = fullPalette32[*lineBuffer];3081lineBuffer++;3082int w = width;3083while (w--) {3084if (*gfxData > 0)3085*frameBufferPtr = activePalette[*gfxData];3086--gfxData;3087++frameBufferPtr;3088}3089frameBufferPtr += pitch;3090gfxData -= gfxPitch;3091}3092break;3093default: break;3094}3095#endif3096}3097void DrawSpriteScaled(int direction, int XPos, int YPos, int pivotX, int pivotY, int scaleX, int scaleY, int width, int height, int sprX, int sprY,3098int sheetID)3099{3100#if RETRO_SOFTWARE_RENDER3101int roundedYPos = 0;3102int roundedXPos = 0;3103int truescaleX = 4 * scaleX;3104int truescaleY = 4 * scaleY;3105int widthM1 = width - 1;3106int trueXPos = XPos - (truescaleX * pivotX >> 11);3107width = truescaleX * width >> 11;3108int trueYPos = YPos - (truescaleY * pivotY >> 11);3109height = truescaleY * height >> 11;3110int finalscaleX = (signed int)(float)((float)(2048.0 / (float)truescaleX) * 2048.0);3111int finalscaleY = (signed int)(float)((float)(2048.0 / (float)truescaleY) * 2048.0);3112if (width + trueXPos > GFX_LINESIZE) {3113width = GFX_LINESIZE - trueXPos;3114}31153116if (direction) {3117if (trueXPos < 0) {3118widthM1 -= trueXPos * -finalscaleX >> 11;3119roundedXPos = (ushort)trueXPos * -(short)finalscaleX & 0x7FF;3120width += trueXPos;3121trueXPos = 0;3122}3123}3124else if (trueXPos < 0) {3125sprX += trueXPos * -finalscaleX >> 11;3126roundedXPos = (ushort)trueXPos * -(short)finalscaleX & 0x7FF;3127width += trueXPos;3128trueXPos = 0;3129}31303131if (height + trueYPos > SCREEN_YSIZE) {3132height = SCREEN_YSIZE - trueYPos;3133}3134if (trueYPos < 0) {3135sprY += trueYPos * -finalscaleY >> 11;3136roundedYPos = (ushort)trueYPos * -(short)finalscaleY & 0x7FF;3137height += trueYPos;3138trueYPos = 0;3139}31403141if (width <= 0 || height <= 0)3142return;31433144GFXSurface *surface = &gfxSurface[sheetID];3145int pitch = GFX_LINESIZE - width;3146int gfxwidth = surface->width;3147byte *lineBuffer = &gfxLineBuffer[trueYPos];3148byte *gfxData = &graphicData[sprX + surface->width * sprY + surface->dataPosition];3149ushort *frameBufferPtr = &Engine.frameBuffer[trueXPos + GFX_LINESIZE * trueYPos];3150if (direction == FLIP_X) {3151byte *gfxDataPtr = &gfxData[widthM1];3152int gfxPitch = 0;3153while (height--) {3154activePalette = fullPalette[*lineBuffer];3155activePalette32 = fullPalette32[*lineBuffer];3156lineBuffer++;3157int roundXPos = roundedXPos;3158int w = width;3159while (w--) {3160if (*gfxDataPtr > 0)3161*frameBufferPtr = activePalette[*gfxDataPtr];3162int offsetX = finalscaleX + roundXPos;3163gfxDataPtr -= offsetX >> 11;3164gfxPitch += offsetX >> 11;3165roundXPos = offsetX & 0x7FF;3166++frameBufferPtr;3167}3168frameBufferPtr += pitch;3169int offsetY = finalscaleY + roundedYPos;3170gfxDataPtr += gfxPitch + (offsetY >> 11) * gfxwidth;3171roundedYPos = offsetY & 0x7FF;3172gfxPitch = 0;3173}3174}3175else {3176int gfxPitch = 0;3177int h = height;3178while (h--) {3179activePalette = fullPalette[*lineBuffer];3180activePalette32 = fullPalette32[*lineBuffer];3181lineBuffer++;3182int roundXPos = roundedXPos;3183int w = width;3184while (w--) {3185if (*gfxData > 0)3186*frameBufferPtr = activePalette[*gfxData];3187int offsetX = finalscaleX + roundXPos;3188gfxData += offsetX >> 11;3189gfxPitch += offsetX >> 11;3190roundXPos = offsetX & 0x7FF;3191++frameBufferPtr;3192}3193frameBufferPtr += pitch;3194int offsetY = finalscaleY + roundedYPos;3195gfxData += (offsetY >> 11) * gfxwidth - gfxPitch;3196roundedYPos = offsetY & 0x7FF;3197gfxPitch = 0;3198}3199}3200#endif3201}3202#if !RETRO_REV023203void DrawScaledChar(int direction, int XPos, int YPos, int pivotX, int pivotY, int scaleX, int scaleY, int width, int height, int sprX, int sprY,3204int sheetID)3205{3206#if RETRO_SOFTWARE_RENDER3207// Not avaliable in SW Render mode3208#endif3209}3210#endif3211void DrawSpriteRotated(int direction, int XPos, int YPos, int pivotX, int pivotY, int sprX, int sprY, int width, int height, int rotation,3212int sheetID)3213{3214#if RETRO_SOFTWARE_RENDER3215int sprXPos = (pivotX + sprX) << 9;3216int sprYPos = (pivotY + sprY) << 9;3217int fullwidth = width + sprX;3218int fullheight = height + sprY;3219int angle = rotation & 0x1FF;3220if (angle < 0)3221angle += 0x200;3222if (angle)3223angle = 0x200 - angle;3224int sine = sin512LookupTable[angle];3225int cosine = cos512LookupTable[angle];3226int xPositions[4];3227int yPositions[4];32283229if (direction == FLIP_X) {3230xPositions[0] = XPos + ((sine * (-pivotY - 2) + cosine * (pivotX + 2)) >> 9);3231yPositions[0] = YPos + ((cosine * (-pivotY - 2) - sine * (pivotX + 2)) >> 9);3232xPositions[1] = XPos + ((sine * (-pivotY - 2) + cosine * (pivotX - width - 2)) >> 9);3233yPositions[1] = YPos + ((cosine * (-pivotY - 2) - sine * (pivotX - width - 2)) >> 9);3234xPositions[2] = XPos + ((sine * (height - pivotY + 2) + cosine * (pivotX + 2)) >> 9);3235yPositions[2] = YPos + ((cosine * (height - pivotY + 2) - sine * (pivotX + 2)) >> 9);3236int a = pivotX - width - 2;3237int b = height - pivotY + 2;3238xPositions[3] = XPos + ((sine * b + cosine * a) >> 9);3239yPositions[3] = YPos + ((cosine * b - sine * a) >> 9);3240}3241else {3242xPositions[0] = XPos + ((sine * (-pivotY - 2) + cosine * (-pivotX - 2)) >> 9);3243yPositions[0] = YPos + ((cosine * (-pivotY - 2) - sine * (-pivotX - 2)) >> 9);3244xPositions[1] = XPos + ((sine * (-pivotY - 2) + cosine * (width - pivotX + 2)) >> 9);3245yPositions[1] = YPos + ((cosine * (-pivotY - 2) - sine * (width - pivotX + 2)) >> 9);3246xPositions[2] = XPos + ((sine * (height - pivotY + 2) + cosine * (-pivotX - 2)) >> 9);3247yPositions[2] = YPos + ((cosine * (height - pivotY + 2) - sine * (-pivotX - 2)) >> 9);3248int a = width - pivotX + 2;3249int b = height - pivotY + 2;3250xPositions[3] = XPos + ((sine * b + cosine * a) >> 9);3251yPositions[3] = YPos + ((cosine * b - sine * a) >> 9);3252}32533254int left = GFX_LINESIZE;3255for (int i = 0; i < 4; ++i) {3256if (xPositions[i] < left)3257left = xPositions[i];3258}3259if (left < 0)3260left = 0;32613262int right = 0;3263for (int i = 0; i < 4; ++i) {3264if (xPositions[i] > right)3265right = xPositions[i];3266}3267if (right > GFX_LINESIZE)3268right = GFX_LINESIZE;3269int maxX = right - left;32703271int top = SCREEN_YSIZE;3272for (int i = 0; i < 4; ++i) {3273if (yPositions[i] < top)3274top = yPositions[i];3275}3276if (top < 0)3277top = 0;32783279int bottom = 0;3280for (int i = 0; i < 4; ++i) {3281if (yPositions[i] > bottom)3282bottom = yPositions[i];3283}3284if (bottom > SCREEN_YSIZE)3285bottom = SCREEN_YSIZE;3286int maxY = bottom - top;32873288if (maxX <= 0 || maxY <= 0)3289return;32903291GFXSurface *surface = &gfxSurface[sheetID];3292int pitch = GFX_LINESIZE - maxX;3293int lineSize = surface->widthShift;3294ushort *frameBufferPtr = &Engine.frameBuffer[left + GFX_LINESIZE * top];3295byte *lineBuffer = &gfxLineBuffer[top];3296int startX = left - XPos;3297int startY = top - YPos;3298int shiftPivot = (sprX << 9) - 1;3299fullwidth <<= 9;3300int shiftheight = (sprY << 9) - 1;3301fullheight <<= 9;3302byte *gfxData = &graphicData[surface->dataPosition];3303if (cosine < 0 || sine < 0)3304sprYPos += sine + cosine;33053306if (direction == FLIP_X) {3307int drawX = sprXPos - (cosine * startX - sine * startY) - 0x100;3308int drawY = cosine * startY + sprYPos + sine * startX;3309while (maxY--) {3310activePalette = fullPalette[*lineBuffer];3311activePalette32 = fullPalette32[*lineBuffer];3312lineBuffer++;3313int finalX = drawX;3314int finalY = drawY;3315int w = maxX;3316while (w--) {3317if (finalX > shiftPivot && finalX < fullwidth && finalY > shiftheight && finalY < fullheight) {3318byte index = gfxData[(finalY >> 9 << lineSize) + (finalX >> 9)];3319if (index > 0)3320*frameBufferPtr = activePalette[index];3321}3322++frameBufferPtr;3323finalX -= cosine;3324finalY += sine;3325}3326drawX += sine;3327drawY += cosine;3328frameBufferPtr += pitch;3329}3330}3331else {3332int drawX = sprXPos + cosine * startX - sine * startY;3333int drawY = cosine * startY + sprYPos + sine * startX;3334while (maxY--) {3335activePalette = fullPalette[*lineBuffer];3336activePalette32 = fullPalette32[*lineBuffer];3337lineBuffer++;3338int finalX = drawX;3339int finalY = drawY;3340int w = maxX;3341while (w--) {3342if (finalX > shiftPivot && finalX < fullwidth && finalY > shiftheight && finalY < fullheight) {3343byte index = gfxData[(finalY >> 9 << lineSize) + (finalX >> 9)];3344if (index > 0)3345*frameBufferPtr = activePalette[index];3346}3347++frameBufferPtr;3348finalX += cosine;3349finalY += sine;3350}3351drawX -= sine;3352drawY += cosine;3353frameBufferPtr += pitch;3354}3355}3356#endif3357}33583359void DrawSpriteRotozoom(int direction, int XPos, int YPos, int pivotX, int pivotY, int sprX, int sprY, int width, int height, int rotation, int scale,3360int sheetID)3361{3362#if RETRO_SOFTWARE_RENDER3363if (scale == 0)3364return;33653366int sprXPos = (pivotX + sprX) << 9;3367int sprYPos = (pivotY + sprY) << 9;3368int fullwidth = width + sprX;3369int fullheight = height + sprY;3370int angle = rotation & 0x1FF;3371if (angle < 0)3372angle += 0x200;3373if (angle)3374angle = 0x200 - angle;3375int sine = scale * sin512LookupTable[angle] >> 9;3376int cosine = scale * cos512LookupTable[angle] >> 9;3377int xPositions[4];3378int yPositions[4];33793380if (direction == FLIP_X) {3381xPositions[0] = XPos + ((sine * (-pivotY - 2) + cosine * (pivotX + 2)) >> 9);3382yPositions[0] = YPos + ((cosine * (-pivotY - 2) - sine * (pivotX + 2)) >> 9);3383xPositions[1] = XPos + ((sine * (-pivotY - 2) + cosine * (pivotX - width - 2)) >> 9);3384yPositions[1] = YPos + ((cosine * (-pivotY - 2) - sine * (pivotX - width - 2)) >> 9);3385xPositions[2] = XPos + ((sine * (height - pivotY + 2) + cosine * (pivotX + 2)) >> 9);3386yPositions[2] = YPos + ((cosine * (height - pivotY + 2) - sine * (pivotX + 2)) >> 9);3387int a = pivotX - width - 2;3388int b = height - pivotY + 2;3389xPositions[3] = XPos + ((sine * b + cosine * a) >> 9);3390yPositions[3] = YPos + ((cosine * b - sine * a) >> 9);3391}3392else {3393xPositions[0] = XPos + ((sine * (-pivotY - 2) + cosine * (-pivotX - 2)) >> 9);3394yPositions[0] = YPos + ((cosine * (-pivotY - 2) - sine * (-pivotX - 2)) >> 9);3395xPositions[1] = XPos + ((sine * (-pivotY - 2) + cosine * (width - pivotX + 2)) >> 9);3396yPositions[1] = YPos + ((cosine * (-pivotY - 2) - sine * (width - pivotX + 2)) >> 9);3397xPositions[2] = XPos + ((sine * (height - pivotY + 2) + cosine * (-pivotX - 2)) >> 9);3398yPositions[2] = YPos + ((cosine * (height - pivotY + 2) - sine * (-pivotX - 2)) >> 9);3399int a = width - pivotX + 2;3400int b = height - pivotY + 2;3401xPositions[3] = XPos + ((sine * b + cosine * a) >> 9);3402yPositions[3] = YPos + ((cosine * b - sine * a) >> 9);3403}3404int truescale = (signed int)(float)((float)(512.0 / (float)scale) * 512.0);3405sine = truescale * sin512LookupTable[angle] >> 9;3406cosine = truescale * cos512LookupTable[angle] >> 9;34073408int left = GFX_LINESIZE;3409for (int i = 0; i < 4; ++i) {3410if (xPositions[i] < left)3411left = xPositions[i];3412}3413if (left < 0)3414left = 0;34153416int right = 0;3417for (int i = 0; i < 4; ++i) {3418if (xPositions[i] > right)3419right = xPositions[i];3420}3421if (right > GFX_LINESIZE)3422right = GFX_LINESIZE;3423int maxX = right - left;34243425int top = SCREEN_YSIZE;3426for (int i = 0; i < 4; ++i) {3427if (yPositions[i] < top)3428top = yPositions[i];3429}3430if (top < 0)3431top = 0;34323433int bottom = 0;3434for (int i = 0; i < 4; ++i) {3435if (yPositions[i] > bottom)3436bottom = yPositions[i];3437}3438if (bottom > SCREEN_YSIZE)3439bottom = SCREEN_YSIZE;3440int maxY = bottom - top;34413442if (maxX <= 0 || maxY <= 0)3443return;34443445GFXSurface *surface = &gfxSurface[sheetID];3446int pitch = GFX_LINESIZE - maxX;3447int lineSize = surface->widthShift;3448ushort *frameBufferPtr = &Engine.frameBuffer[left + GFX_LINESIZE * top];3449byte *lineBuffer = &gfxLineBuffer[top];3450int startX = left - XPos;3451int startY = top - YPos;3452int shiftPivot = (sprX << 9) - 1;3453fullwidth <<= 9;3454int shiftheight = (sprY << 9) - 1;3455fullheight <<= 9;3456byte *gfxData = &graphicData[surface->dataPosition];3457if (cosine < 0 || sine < 0)3458sprYPos += sine + cosine;34593460if (direction == FLIP_X) {3461int drawX = sprXPos - (cosine * startX - sine * startY) - (truescale >> 1);3462int drawY = cosine * startY + sprYPos + sine * startX;3463while (maxY--) {3464activePalette = fullPalette[*lineBuffer];3465activePalette32 = fullPalette32[*lineBuffer];3466lineBuffer++;3467int finalX = drawX;3468int finalY = drawY;3469int w = maxX;3470while (w--) {3471if (finalX > shiftPivot && finalX < fullwidth && finalY > shiftheight && finalY < fullheight) {3472byte index = gfxData[(finalY >> 9 << lineSize) + (finalX >> 9)];3473if (index > 0)3474*frameBufferPtr = activePalette[index];3475}3476++frameBufferPtr;3477finalX -= cosine;3478finalY += sine;3479}3480drawX += sine;3481drawY += cosine;3482frameBufferPtr += pitch;3483}3484}3485else {3486int drawX = sprXPos + cosine * startX - sine * startY;3487int drawY = cosine * startY + sprYPos + sine * startX;3488while (maxY--) {3489activePalette = fullPalette[*lineBuffer];3490activePalette32 = fullPalette32[*lineBuffer];3491lineBuffer++;3492int finalX = drawX;3493int finalY = drawY;3494int w = maxX;3495while (w--) {3496if (finalX > shiftPivot && finalX < fullwidth && finalY > shiftheight && finalY < fullheight) {3497byte index = gfxData[(finalY >> 9 << lineSize) + (finalX >> 9)];3498if (index > 0)3499*frameBufferPtr = activePalette[index];3500}3501++frameBufferPtr;3502finalX += cosine;3503finalY += sine;3504}3505drawX -= sine;3506drawY += cosine;3507frameBufferPtr += pitch;3508}3509}3510#endif3511}35123513void DrawBlendedSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int sheetID)3514{3515#if RETRO_SOFTWARE_RENDER3516if (width + XPos > GFX_LINESIZE)3517width = GFX_LINESIZE - XPos;3518if (XPos < 0) {3519sprX -= XPos;3520width += XPos;3521XPos = 0;3522}3523if (height + YPos > SCREEN_YSIZE)3524height = SCREEN_YSIZE - YPos;3525if (YPos < 0) {3526sprY -= YPos;3527height += YPos;3528YPos = 0;3529}3530if (width <= 0 || height <= 0)3531return;35323533GFXSurface *surface = &gfxSurface[sheetID];3534int pitch = GFX_LINESIZE - width;3535int gfxPitch = surface->width - width;3536byte *lineBuffer = &gfxLineBuffer[YPos];3537byte *gfxData = &graphicData[sprX + surface->width * sprY + surface->dataPosition];3538ushort *frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];3539while (height--) {3540activePalette = fullPalette[*lineBuffer];3541activePalette32 = fullPalette32[*lineBuffer];3542lineBuffer++;3543int w = width;3544while (w--) {3545if (*gfxData > 0)3546*frameBufferPtr = ((activePalette[*gfxData] & 0xF7DE) >> 1) + ((*frameBufferPtr & 0xF7DE) >> 1);3547++gfxData;3548++frameBufferPtr;3549}3550frameBufferPtr += pitch;3551gfxData += gfxPitch;3552}3553#endif3554}3555void DrawAlphaBlendedSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int alpha, int sheetID)3556{3557if (alpha > 0xFF)3558alpha = 0xFF;3559#if RETRO_SOFTWARE_RENDER3560if (width + XPos > GFX_LINESIZE)3561width = GFX_LINESIZE - XPos;3562if (XPos < 0) {3563sprX -= XPos;3564width += XPos;3565XPos = 0;3566}3567if (height + YPos > SCREEN_YSIZE)3568height = SCREEN_YSIZE - YPos;3569if (YPos < 0) {3570sprY -= YPos;3571height += YPos;3572YPos = 0;3573}3574if (width <= 0 || height <= 0 || alpha <= 0)3575return;35763577GFXSurface *surface = &gfxSurface[sheetID];3578int pitch = GFX_LINESIZE - width;3579int gfxPitch = surface->width - width;3580byte *lineBuffer = &gfxLineBuffer[YPos];3581byte *gfxData = &graphicData[sprX + surface->width * sprY + surface->dataPosition];3582ushort *frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];3583if (alpha == 0xFF) {3584while (height--) {3585activePalette = fullPalette[*lineBuffer];3586activePalette32 = fullPalette32[*lineBuffer];3587lineBuffer++;3588int w = width;3589while (w--) {3590if (*gfxData > 0)3591*frameBufferPtr = activePalette[*gfxData];3592++gfxData;3593++frameBufferPtr;3594}3595frameBufferPtr += pitch;3596gfxData += gfxPitch;3597}3598}3599else {3600ushort *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];3601ushort *pixelBlend = &blendLookupTable[0x20 * alpha];36023603while (height--) {3604activePalette = fullPalette[*lineBuffer];3605activePalette32 = fullPalette32[*lineBuffer];3606lineBuffer++;3607int w = width;3608while (w--) {3609if (*gfxData > 0) {3610ushort color = activePalette[*gfxData];36113612int R = (fbufferBlend[(*frameBufferPtr & 0xF800) >> 11] + pixelBlend[(color & 0xF800) >> 11]) << 11;3613int G = (fbufferBlend[(*frameBufferPtr & 0x7E0) >> 6] + pixelBlend[(color & 0x7E0) >> 6]) << 6;3614int B = fbufferBlend[*frameBufferPtr & 0x1F] + pixelBlend[color & 0x1F];36153616*frameBufferPtr = R | G | B;3617}3618++gfxData;3619++frameBufferPtr;3620}3621frameBufferPtr += pitch;3622gfxData += gfxPitch;3623}3624}3625#endif3626}3627void DrawAdditiveBlendedSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int alpha, int sheetID)3628{3629if (alpha > 0xFF)3630alpha = 0xFF;3631#if RETRO_SOFTWARE_RENDER3632if (width + XPos > GFX_LINESIZE)3633width = GFX_LINESIZE - XPos;3634if (XPos < 0) {3635sprX -= XPos;3636width += XPos;3637XPos = 0;3638}3639if (height + YPos > SCREEN_YSIZE)3640height = SCREEN_YSIZE - YPos;3641if (YPos < 0) {3642sprY -= YPos;3643height += YPos;3644YPos = 0;3645}3646if (width <= 0 || height <= 0 || alpha <= 0)3647return;36483649ushort *blendTablePtr = &blendLookupTable[0x20 * alpha];3650GFXSurface *surface = &gfxSurface[sheetID];3651int pitch = GFX_LINESIZE - width;3652int gfxPitch = surface->width - width;3653byte *lineBuffer = &gfxLineBuffer[YPos];3654byte *gfxData = &graphicData[sprX + surface->width * sprY + surface->dataPosition];3655ushort *frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];36563657while (height--) {3658activePalette = fullPalette[*lineBuffer];3659activePalette32 = fullPalette32[*lineBuffer];3660lineBuffer++;3661int w = width;3662while (w--) {3663if (*gfxData > 0) {3664ushort color = activePalette[*gfxData];36653666int R = minVal((blendTablePtr[(color & 0xF800) >> 11] << 11) + (*frameBufferPtr & 0xF800), 0xF800);3667int G = minVal((blendTablePtr[(color & 0x7E0) >> 6] << 6) + (*frameBufferPtr & 0x7E0), 0x7E0);3668int B = minVal(blendTablePtr[color & 0x1F] + (*frameBufferPtr & 0x1F), 0x1F);36693670*frameBufferPtr = R | G | B;3671}3672++gfxData;3673++frameBufferPtr;3674}3675frameBufferPtr += pitch;3676gfxData += gfxPitch;3677}3678#endif3679}3680void DrawSubtractiveBlendedSprite(int XPos, int YPos, int width, int height, int sprX, int sprY, int alpha, int sheetID)3681{3682if (alpha > 0xFF)3683alpha = 0xFF;36843685#if RETRO_SOFTWARE_RENDER3686if (width + XPos > GFX_LINESIZE)3687width = GFX_LINESIZE - XPos;3688if (XPos < 0) {3689sprX -= XPos;3690width += XPos;3691XPos = 0;3692}3693if (height + YPos > SCREEN_YSIZE)3694height = SCREEN_YSIZE - YPos;3695if (YPos < 0) {3696sprY -= YPos;3697height += YPos;3698YPos = 0;3699}3700if (width <= 0 || height <= 0 || alpha <= 0)3701return;37023703ushort *subBlendTable = &subtractLookupTable[0x20 * alpha];3704GFXSurface *surface = &gfxSurface[sheetID];3705int pitch = GFX_LINESIZE - width;3706int gfxPitch = surface->width - width;3707byte *lineBuffer = &gfxLineBuffer[YPos];3708byte *gfxData = &graphicData[sprX + surface->width * sprY + surface->dataPosition];3709ushort *frameBufferPtr = &Engine.frameBuffer[XPos + GFX_LINESIZE * YPos];37103711while (height--) {3712activePalette = fullPalette[*lineBuffer];3713activePalette32 = fullPalette32[*lineBuffer];3714lineBuffer++;3715int w = width;3716while (w--) {3717if (*gfxData > 0) {3718ushort color = activePalette[*gfxData];37193720int R = maxVal((*frameBufferPtr & 0xF800) - (subBlendTable[(color & 0xF800) >> 11] << 11), 0);3721int G = maxVal((*frameBufferPtr & 0x7E0) - (subBlendTable[(color & 0x7E0) >> 6] << 6), 0);3722int B = maxVal((*frameBufferPtr & 0x1F) - subBlendTable[color & 0x1F], 0);37233724*frameBufferPtr = R | G | B;3725}3726++gfxData;3727++frameBufferPtr;3728}3729frameBufferPtr += pitch;3730gfxData += gfxPitch;3731}3732#endif3733}37343735void DrawObjectAnimation(void *objScr, void *ent, int XPos, int YPos)3736{3737ObjectScript *objectScript = (ObjectScript *)objScr;3738Entity *entity = (Entity *)ent;3739SpriteAnimation *sprAnim = &animationList[objectScript->animFile->aniListOffset + entity->animation];3740SpriteFrame *frame = &animFrames[sprAnim->frameListOffset + entity->frame];3741int rotation = 0;37423743switch (sprAnim->rotationStyle) {3744case ROTSTYLE_NONE:3745switch (entity->direction) {3746case FLIP_NONE:3747DrawSpriteFlipped(frame->pivotX + XPos, frame->pivotY + YPos, frame->width, frame->height, frame->sprX, frame->sprY, FLIP_NONE,3748frame->sheetID);3749break;37503751case FLIP_X:3752DrawSpriteFlipped(XPos - frame->width - frame->pivotX, frame->pivotY + YPos, frame->width, frame->height, frame->sprX,3753frame->sprY, FLIP_X, frame->sheetID);3754break;3755case FLIP_Y:37563757DrawSpriteFlipped(frame->pivotX + XPos, YPos - frame->height - frame->pivotY, frame->width, frame->height, frame->sprX,3758frame->sprY, FLIP_Y, frame->sheetID);3759break;37603761case FLIP_XY:3762DrawSpriteFlipped(XPos - frame->width - frame->pivotX, YPos - frame->height - frame->pivotY, frame->width, frame->height,3763frame->sprX, frame->sprY, FLIP_XY, frame->sheetID);3764break;37653766default: break;3767}3768break;37693770case ROTSTYLE_FULL:3771DrawSpriteRotated(entity->direction, XPos, YPos, -frame->pivotX, -frame->pivotY, frame->sprX, frame->sprY, frame->width, frame->height,3772entity->rotation, frame->sheetID);3773break;37743775case ROTSTYLE_45DEG:3776if (entity->rotation >= 0x100)3777DrawSpriteRotated(entity->direction, XPos, YPos, -frame->pivotX, -frame->pivotY, frame->sprX, frame->sprY, frame->width,3778frame->height, 0x200 - ((0x214 - entity->rotation) >> 6 << 6), frame->sheetID);3779else3780DrawSpriteRotated(entity->direction, XPos, YPos, -frame->pivotX, -frame->pivotY, frame->sprX, frame->sprY, frame->width,3781frame->height, (entity->rotation + 20) >> 6 << 6, frame->sheetID);3782break;37833784case ROTSTYLE_STATICFRAMES: {3785if (entity->rotation >= 0x100)3786rotation = 8 - ((532 - entity->rotation) >> 6);3787else3788rotation = (entity->rotation + 20) >> 6;3789int frameID = entity->frame;3790switch (rotation) {3791case 0: // 0 deg3792case 8: // 360 deg3793rotation = 0x00;3794break;37953796case 1: // 45 deg3797frameID += sprAnim->frameCount;3798if (entity->direction)3799rotation = 0;3800else3801rotation = 0x80;3802break;38033804case 2: // 90 deg3805rotation = 0x80;3806break;38073808case 3: // 135 deg3809frameID += sprAnim->frameCount;3810if (entity->direction)3811rotation = 0x80;3812else3813rotation = 0x100;3814break;38153816case 4: // 180 deg3817rotation = 0x100;3818break;38193820case 5: // 225 deg3821frameID += sprAnim->frameCount;3822if (entity->direction)3823rotation = 0x100;3824else3825rotation = 384;3826break;38273828case 6: // 270 deg3829rotation = 384;3830break;38313832case 7: // 315 deg3833frameID += sprAnim->frameCount;3834if (entity->direction)3835rotation = 384;3836else3837rotation = 0;3838break;38393840default: break;3841}38423843frame = &animFrames[sprAnim->frameListOffset + frameID];3844DrawSpriteRotated(entity->direction, XPos, YPos, -frame->pivotX, -frame->pivotY, frame->sprX, frame->sprY, frame->width, frame->height,3845rotation, frame->sheetID);3846// DrawSpriteRotozoom(entity->direction, XPos, YPos, -frame->pivotX, -frame->pivotY, frame->sprX, frame->sprY, frame->width,3847// frame->height,3848// rotation, entity->scale, frame->sheetID);3849break;3850}38513852default: break;3853}3854}38553856void DrawFace(void *v, uint color)3857{3858Vertex *verts = (Vertex *)v;3859int alpha = (color & 0x7F000000) >> 23;3860if (alpha < 1)3861return;38623863if (alpha > 0xFF)3864alpha = 0xFF;38653866if (verts[0].x < 0 && verts[1].x < 0 && verts[2].x < 0 && verts[3].x < 0)3867return;38683869if (verts[0].x > GFX_LINESIZE && verts[1].x > GFX_LINESIZE && verts[2].x > GFX_LINESIZE && verts[3].x > GFX_LINESIZE)3870return;38713872if (verts[0].y < 0 && verts[1].y < 0 && verts[2].y < 0 && verts[3].y < 0)3873return;38743875if (verts[0].y > SCREEN_YSIZE && verts[1].y > SCREEN_YSIZE && verts[2].y > SCREEN_YSIZE && verts[3].y > SCREEN_YSIZE)3876return;38773878if (verts[0].x == verts[1].x && verts[1].x == verts[2].x && verts[2].x == verts[3].x)3879return;38803881if (verts[0].y == verts[1].y && verts[1].y == verts[2].y && verts[2].y == verts[3].y)3882return;38833884#if RETRO_SOFTWARE_RENDER3885int vertexA = 0;3886int vertexB = 1;3887int vertexC = 2;3888int vertexD = 3;3889if (verts[1].y < verts[0].y) {3890vertexA = 1;3891vertexB = 0;3892}3893if (verts[2].y < verts[vertexA].y) {3894int temp = vertexA;3895vertexA = 2;3896vertexC = temp;3897}3898if (verts[3].y < verts[vertexA].y) {3899int temp = vertexA;3900vertexA = 3;3901vertexD = temp;3902}3903if (verts[vertexC].y < verts[vertexB].y) {3904int temp = vertexB;3905vertexB = vertexC;3906vertexC = temp;3907}3908if (verts[vertexD].y < verts[vertexB].y) {3909int temp = vertexB;3910vertexB = vertexD;3911vertexD = temp;3912}3913if (verts[vertexD].y < verts[vertexC].y) {3914int temp = vertexC;3915vertexC = vertexD;3916vertexD = temp;3917}39183919int faceTop = verts[vertexA].y;3920int faceBottom = verts[vertexD].y;3921if (faceTop < 0)3922faceTop = 0;3923if (faceBottom > SCREEN_YSIZE)3924faceBottom = SCREEN_YSIZE;3925for (int i = faceTop; i < faceBottom; ++i) {3926faceLineStart[i] = 100000;3927faceLineEnd[i] = -100000;3928}39293930ProcessScanEdge(&verts[vertexA], &verts[vertexB]);3931ProcessScanEdge(&verts[vertexA], &verts[vertexC]);3932ProcessScanEdge(&verts[vertexA], &verts[vertexD]);3933ProcessScanEdge(&verts[vertexB], &verts[vertexC]);3934ProcessScanEdge(&verts[vertexC], &verts[vertexD]);3935ProcessScanEdge(&verts[vertexB], &verts[vertexD]);39363937ushort color16 = PACK_RGB888(((color >> 16) & 0xFF), ((color >> 8) & 0xFF), ((color >> 0) & 0xFF));39383939ushort *frameBufferPtr = &Engine.frameBuffer[GFX_LINESIZE * faceTop];3940if (alpha == 255) {3941while (faceTop < faceBottom) {3942int startX = faceLineStart[faceTop];3943int endX = faceLineEnd[faceTop];3944if (startX >= GFX_LINESIZE || endX <= 0) {3945frameBufferPtr += GFX_LINESIZE;3946}3947else {3948if (startX < 0)3949startX = 0;3950if (endX > GFX_LINESIZE_MINUSONE)3951endX = GFX_LINESIZE_MINUSONE;3952ushort *fbPtr = &frameBufferPtr[startX];3953frameBufferPtr += GFX_LINESIZE;3954int vertexwidth = endX - startX + 1;3955while (vertexwidth--) {3956*fbPtr = color16;3957++fbPtr;3958}3959}3960++faceTop;3961}3962}3963else {3964ushort *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];3965ushort *pixelBlend = &blendLookupTable[0x20 * alpha];39663967while (faceTop < faceBottom) {3968int startX = faceLineStart[faceTop];3969int endX = faceLineEnd[faceTop];3970if (startX >= GFX_LINESIZE || endX <= 0) {3971frameBufferPtr += GFX_LINESIZE;3972}3973else {3974if (startX < 0)3975startX = 0;3976if (endX > GFX_LINESIZE_MINUSONE)3977endX = GFX_LINESIZE_MINUSONE;3978ushort *fbPtr = &frameBufferPtr[startX];3979frameBufferPtr += GFX_LINESIZE;3980int vertexwidth = endX - startX + 1;3981while (vertexwidth--) {3982int R = (fbufferBlend[(*fbPtr & 0xF800) >> 11] + pixelBlend[(color16 & 0xF800) >> 11]) << 11;3983int G = (fbufferBlend[(*fbPtr & 0x7E0) >> 6] + pixelBlend[(color16 & 0x7E0) >> 6]) << 6;3984int B = fbufferBlend[*fbPtr & 0x1F] + pixelBlend[color16 & 0x1F];39853986*fbPtr = R | G | B;3987++fbPtr;3988}3989}3990++faceTop;3991}3992}3993#endif3994}3995void DrawFadedFace(void *v, uint color, uint fogColor, int alpha)3996{3997Vertex *verts = (Vertex *)v;3998if (alpha > 0xFF)3999alpha = 0xFF;40004001if (alpha < 1)4002return;40034004if (verts[0].x < 0 && verts[1].x < 0 && verts[2].x < 0 && verts[3].x < 0)4005return;40064007if (verts[0].x > GFX_LINESIZE && verts[1].x > GFX_LINESIZE && verts[2].x > GFX_LINESIZE && verts[3].x > GFX_LINESIZE)4008return;40094010if (verts[0].y < 0 && verts[1].y < 0 && verts[2].y < 0 && verts[3].y < 0)4011return;40124013if (verts[0].y > SCREEN_YSIZE && verts[1].y > SCREEN_YSIZE && verts[2].y > SCREEN_YSIZE && verts[3].y > SCREEN_YSIZE)4014return;40154016if (verts[0].x == verts[1].x && verts[1].x == verts[2].x && verts[2].x == verts[3].x)4017return;40184019if (verts[0].y == verts[1].y && verts[1].y == verts[2].y && verts[2].y == verts[3].y)4020return;40214022#if RETRO_SOFTWARE_RENDER4023int vertexA = 0;4024int vertexB = 1;4025int vertexC = 2;4026int vertexD = 3;4027if (verts[1].y < verts[0].y) {4028vertexA = 1;4029vertexB = 0;4030}4031if (verts[2].y < verts[vertexA].y) {4032int temp = vertexA;4033vertexA = 2;4034vertexC = temp;4035}4036if (verts[3].y < verts[vertexA].y) {4037int temp = vertexA;4038vertexA = 3;4039vertexD = temp;4040}4041if (verts[vertexC].y < verts[vertexB].y) {4042int temp = vertexB;4043vertexB = vertexC;4044vertexC = temp;4045}4046if (verts[vertexD].y < verts[vertexB].y) {4047int temp = vertexB;4048vertexB = vertexD;4049vertexD = temp;4050}4051if (verts[vertexD].y < verts[vertexC].y) {4052int temp = vertexC;4053vertexC = vertexD;4054vertexD = temp;4055}40564057int faceTop = verts[vertexA].y;4058int faceBottom = verts[vertexD].y;4059if (faceTop < 0)4060faceTop = 0;4061if (faceBottom > SCREEN_YSIZE)4062faceBottom = SCREEN_YSIZE;4063for (int i = faceTop; i < faceBottom; ++i) {4064faceLineStart[i] = 100000;4065faceLineEnd[i] = -100000;4066}40674068ProcessScanEdge(&verts[vertexA], &verts[vertexB]);4069ProcessScanEdge(&verts[vertexA], &verts[vertexC]);4070ProcessScanEdge(&verts[vertexA], &verts[vertexD]);4071ProcessScanEdge(&verts[vertexB], &verts[vertexC]);4072ProcessScanEdge(&verts[vertexC], &verts[vertexD]);4073ProcessScanEdge(&verts[vertexB], &verts[vertexD]);40744075ushort color16 = PACK_RGB888(((color >> 16) & 0xFF), ((color >> 8) & 0xFF), ((color >> 0) & 0xFF));4076ushort fogColor16 = PACK_RGB888(((fogColor >> 16) & 0xFF), ((fogColor >> 8) & 0xFF), ((fogColor >> 0) & 0xFF));40774078ushort *frameBufferPtr = &Engine.frameBuffer[GFX_LINESIZE * faceTop];4079ushort *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];4080ushort *pixelBlend = &blendLookupTable[0x20 * alpha];40814082while (faceTop < faceBottom) {4083int startX = faceLineStart[faceTop];4084int endX = faceLineEnd[faceTop];4085if (startX >= GFX_LINESIZE || endX <= 0) {4086frameBufferPtr += GFX_LINESIZE;4087}4088else {4089if (startX < 0)4090startX = 0;4091if (endX > GFX_LINESIZE_MINUSONE)4092endX = GFX_LINESIZE_MINUSONE;4093ushort *fbPtr = &frameBufferPtr[startX];4094frameBufferPtr += GFX_LINESIZE;4095int vertexwidth = endX - startX + 1;4096while (vertexwidth--) {4097int R = (fbufferBlend[(fogColor16 & 0xF800) >> 11] + pixelBlend[(color16 & 0xF800) >> 11]) << 11;4098int G = (fbufferBlend[(fogColor16 & 0x7E0) >> 6] + pixelBlend[(color16 & 0x7E0) >> 6]) << 6;4099int B = fbufferBlend[fogColor16 & 0x1F] + pixelBlend[color16 & 0x1F];41004101*fbPtr = R | G | B;4102++fbPtr;4103}4104}4105++faceTop;4106}4107#endif4108}4109void DrawTexturedFace(void *v, byte sheetID)4110{4111Vertex *verts = (Vertex *)v;41124113if (verts[0].x < 0 && verts[1].x < 0 && verts[2].x < 0 && verts[3].x < 0)4114return;4115if (verts[0].x > GFX_LINESIZE && verts[1].x > GFX_LINESIZE && verts[2].x > GFX_LINESIZE && verts[3].x > GFX_LINESIZE)4116return;4117if (verts[0].y < 0 && verts[1].y < 0 && verts[2].y < 0 && verts[3].y < 0)4118return;4119if (verts[0].y > SCREEN_YSIZE && verts[1].y > SCREEN_YSIZE && verts[2].y > SCREEN_YSIZE && verts[3].y > SCREEN_YSIZE)4120return;4121if (verts[0].x == verts[1].x && verts[1].x == verts[2].x && verts[2].x == verts[3].x)4122return;4123if (verts[0].y == verts[1].y && verts[1].y == verts[2].y && verts[2].y == verts[3].y)4124return;41254126#if RETRO_SOFTWARE_RENDER4127int vertexA = 0;4128int vertexB = 1;4129int vertexC = 2;4130int vertexD = 3;4131if (verts[1].y < verts[0].y) {4132vertexA = 1;4133vertexB = 0;4134}4135if (verts[2].y < verts[vertexA].y) {4136int temp = vertexA;4137vertexA = 2;4138vertexC = temp;4139}4140if (verts[3].y < verts[vertexA].y) {4141int temp = vertexA;4142vertexA = 3;4143vertexD = temp;4144}4145if (verts[vertexC].y < verts[vertexB].y) {4146int temp = vertexB;4147vertexB = vertexC;4148vertexC = temp;4149}4150if (verts[vertexD].y < verts[vertexB].y) {4151int temp = vertexB;4152vertexB = vertexD;4153vertexD = temp;4154}4155if (verts[vertexD].y < verts[vertexC].y) {4156int temp = vertexC;4157vertexC = vertexD;4158vertexD = temp;4159}41604161int faceTop = verts[vertexA].y;4162int faceBottom = verts[vertexD].y;4163if (faceTop < 0)4164faceTop = 0;4165if (faceBottom > SCREEN_YSIZE)4166faceBottom = SCREEN_YSIZE;4167for (int i = faceTop; i < faceBottom; ++i) {4168faceLineStart[i] = 100000;4169faceLineEnd[i] = -100000;4170}41714172ProcessScanEdgeUV(&verts[vertexA], &verts[vertexB]);4173ProcessScanEdgeUV(&verts[vertexA], &verts[vertexC]);4174ProcessScanEdgeUV(&verts[vertexA], &verts[vertexD]);4175ProcessScanEdgeUV(&verts[vertexB], &verts[vertexC]);4176ProcessScanEdgeUV(&verts[vertexC], &verts[vertexD]);4177ProcessScanEdgeUV(&verts[vertexB], &verts[vertexD]);41784179ushort *frameBufferPtr = &Engine.frameBuffer[GFX_LINESIZE * faceTop];4180byte *sheetPtr = &graphicData[gfxSurface[sheetID].dataPosition];4181int shiftwidth = gfxSurface[sheetID].widthShift;4182byte *lineBuffer = &gfxLineBuffer[faceTop];4183while (faceTop < faceBottom) {4184activePalette = fullPalette[*lineBuffer];4185activePalette32 = fullPalette32[*lineBuffer];4186lineBuffer++;4187int startX = faceLineStart[faceTop];4188int endX = faceLineEnd[faceTop];4189int UPos = faceLineStartU[faceTop];4190int VPos = faceLineStartV[faceTop];4191if (startX >= GFX_LINESIZE || endX <= 0) {4192frameBufferPtr += GFX_LINESIZE;4193}4194else {4195int posDifference = endX - startX;4196int bufferedUPos = 0;4197int bufferedVPos = 0;4198if (endX == startX) {4199bufferedUPos = 0;4200bufferedVPos = 0;4201}4202else {4203bufferedUPos = (faceLineEndU[faceTop] - UPos) / posDifference;4204bufferedVPos = (faceLineEndV[faceTop] - VPos) / posDifference;4205}4206if (endX > GFX_LINESIZE_MINUSONE)4207posDifference = GFX_LINESIZE_MINUSONE - startX;4208if (startX < 0) {4209posDifference += startX;4210UPos -= startX * bufferedUPos;4211VPos -= startX * bufferedVPos;4212startX = 0;4213}4214ushort *fbPtr = &frameBufferPtr[startX];4215frameBufferPtr += GFX_LINESIZE;4216#if RETRO_REV024217int counter = posDifference;4218#else4219int counter = posDifference + 1;4220#endif4221while (counter--) {4222if (UPos < 0)4223UPos = 0;4224if (VPos < 0)4225VPos = 0;4226ushort index = sheetPtr[(VPos >> 16 << shiftwidth) + (UPos >> 16)];4227if (index > 0)4228*fbPtr = activePalette[index];4229fbPtr++;4230UPos += bufferedUPos;4231VPos += bufferedVPos;4232}4233}4234++faceTop;4235}4236#endif4237}4238void DrawTexturedFaceBlended(void *v, byte sheetID)4239{4240Vertex *verts = (Vertex *)v;4241if (verts[0].x < 0 && verts[1].x < 0 && verts[2].x < 0 && verts[3].x < 0)4242return;42434244if (verts[0].x > GFX_LINESIZE && verts[1].x > GFX_LINESIZE && verts[2].x > GFX_LINESIZE && verts[3].x > GFX_LINESIZE)4245return;42464247if (verts[0].y < 0 && verts[1].y < 0 && verts[2].y < 0 && verts[3].y < 0)4248return;42494250if (verts[0].y > SCREEN_YSIZE && verts[1].y > SCREEN_YSIZE && verts[2].y > SCREEN_YSIZE && verts[3].y > SCREEN_YSIZE)4251return;42524253if (verts[0].x == verts[1].x && verts[1].x == verts[2].x && verts[2].x == verts[3].x)4254return;42554256if (verts[0].y == verts[1].y && verts[1].y == verts[2].y && verts[2].y == verts[3].y)4257return;42584259#if RETRO_SOFTWARE_RENDER4260int vertexA = 0;4261int vertexB = 1;4262int vertexC = 2;4263int vertexD = 3;4264if (verts[1].y < verts[0].y) {4265vertexA = 1;4266vertexB = 0;4267}4268if (verts[2].y < verts[vertexA].y) {4269int temp = vertexA;4270vertexA = 2;4271vertexC = temp;4272}4273if (verts[3].y < verts[vertexA].y) {4274int temp = vertexA;4275vertexA = 3;4276vertexD = temp;4277}4278if (verts[vertexC].y < verts[vertexB].y) {4279int temp = vertexB;4280vertexB = vertexC;4281vertexC = temp;4282}4283if (verts[vertexD].y < verts[vertexB].y) {4284int temp = vertexB;4285vertexB = vertexD;4286vertexD = temp;4287}4288if (verts[vertexD].y < verts[vertexC].y) {4289int temp = vertexC;4290vertexC = vertexD;4291vertexD = temp;4292}42934294int faceTop = verts[vertexA].y;4295int faceBottom = verts[vertexD].y;4296if (faceTop < 0)4297faceTop = 0;4298if (faceBottom > SCREEN_YSIZE)4299faceBottom = SCREEN_YSIZE;4300for (int i = faceTop; i < faceBottom; ++i) {4301faceLineStart[i] = 100000;4302faceLineEnd[i] = -100000;4303}43044305ProcessScanEdgeUV(&verts[vertexA], &verts[vertexB]);4306ProcessScanEdgeUV(&verts[vertexA], &verts[vertexC]);4307ProcessScanEdgeUV(&verts[vertexA], &verts[vertexD]);4308ProcessScanEdgeUV(&verts[vertexB], &verts[vertexC]);4309ProcessScanEdgeUV(&verts[vertexC], &verts[vertexD]);4310ProcessScanEdgeUV(&verts[vertexB], &verts[vertexD]);43114312ushort *frameBufferPtr = &Engine.frameBuffer[GFX_LINESIZE * faceTop];4313byte *sheetPtr = &graphicData[gfxSurface[sheetID].dataPosition];4314int shiftwidth = gfxSurface[sheetID].widthShift;4315byte *lineBuffer = &gfxLineBuffer[faceTop];4316while (faceTop < faceBottom) {4317activePalette = fullPalette[*lineBuffer];4318activePalette32 = fullPalette32[*lineBuffer];4319lineBuffer++;4320int startX = faceLineStart[faceTop];4321int endX = faceLineEnd[faceTop];4322int UPos = faceLineStartU[faceTop];4323int VPos = faceLineStartV[faceTop];4324if (startX >= GFX_LINESIZE || endX <= 0) {4325frameBufferPtr += GFX_LINESIZE;4326}4327else {4328int posDifference = endX - startX;4329int bufferedUPos = 0;4330int bufferedVPos = 0;4331if (endX == startX) {4332bufferedUPos = 0;4333bufferedVPos = 0;4334}4335else {4336bufferedUPos = (faceLineEndU[faceTop] - UPos) / posDifference;4337bufferedVPos = (faceLineEndV[faceTop] - VPos) / posDifference;4338}4339if (endX > GFX_LINESIZE_MINUSONE)4340posDifference = GFX_LINESIZE_MINUSONE - startX;4341if (startX < 0) {4342posDifference += startX;4343UPos -= startX * bufferedUPos;4344VPos -= startX * bufferedVPos;4345startX = 0;4346}4347ushort *fbPtr = &frameBufferPtr[startX];4348frameBufferPtr += GFX_LINESIZE;4349#if RETRO_REV024350int counter = posDifference;4351#else4352int counter = posDifference + 1;4353#endif4354while (counter--) {4355if (UPos < 0)4356UPos = 0;4357if (VPos < 0)4358VPos = 0;4359ushort index = sheetPtr[(VPos >> 16 << shiftwidth) + (UPos >> 16)];4360if (index > 0)4361*fbPtr = ((activePalette[index] & 0xF7BC) >> 1) + ((*fbPtr & 0xF7BC) >> 1);4362fbPtr++;4363UPos += bufferedUPos;4364VPos += bufferedVPos;4365}4366}4367++faceTop;4368}4369#endif4370}43714372#if !RETRO_REV024373void DrawBitmapText(void *menu, int XPos, int YPos, int scale, int spacing, int rowStart, int rowCount)4374{4375TextMenu *tMenu = (TextMenu *)menu;4376int Y = YPos << 9;4377if (rowCount < 0)4378rowCount = tMenu->rowCount;4379if (rowStart + rowCount > tMenu->rowCount)4380rowCount = tMenu->rowCount - rowStart;43814382while (rowCount > 0) {4383int X = XPos << 9;4384for (int i = 0; i < tMenu->entrySize[rowStart]; ++i) {4385ushort c = tMenu->textData[tMenu->entryStart[rowStart] + i];4386FontCharacter *fChar = &fontCharacterList[c];4387#if RETRO_SOFTWARE_RENDER4388DrawSpriteScaled(FLIP_NONE, X >> 9, Y >> 9, -fChar->pivotX, -fChar->pivotY, scale, scale, fChar->width, fChar->height, fChar->srcX,4389fChar->srcY, textMenuSurfaceNo);4390#endif4391X += fChar->xAdvance * scale;4392}4393Y += spacing * scale;4394rowStart++;4395rowCount--;4396}4397}4398#endif43994400void DrawTextMenuEntry(void *menu, int rowID, int XPos, int YPos, int textHighlight)4401{4402TextMenu *tMenu = (TextMenu *)menu;4403int id = tMenu->entryStart[rowID];4404for (int i = 0; i < tMenu->entrySize[rowID]; ++i) {4405DrawSprite(XPos + (i << 3) - (((tMenu->entrySize[rowID] % 2) & (tMenu->alignment == 2)) * 4), YPos, 8, 8, ((tMenu->textData[id] & 0xF) << 3),4406((tMenu->textData[id] >> 4) << 3) + textHighlight, textMenuSurfaceNo);4407id++;4408}4409}4410void DrawStageTextEntry(void *menu, int rowID, int XPos, int YPos, int textHighlight)4411{4412TextMenu *tMenu = (TextMenu *)menu;4413int id = tMenu->entryStart[rowID];4414for (int i = 0; i < tMenu->entrySize[rowID]; ++i) {4415if (i == tMenu->entrySize[rowID] - 1) {4416DrawSprite(XPos + (i << 3), YPos, 8, 8, ((tMenu->textData[id] & 0xF) << 3), ((tMenu->textData[id] >> 4) << 3), textMenuSurfaceNo);4417}4418else {4419DrawSprite(XPos + (i << 3), YPos, 8, 8, ((tMenu->textData[id] & 0xF) << 3), ((tMenu->textData[id] >> 4) << 3) + textHighlight,4420textMenuSurfaceNo);4421}4422id++;4423}4424}4425void DrawBlendedTextMenuEntry(void *menu, int rowID, int XPos, int YPos, int textHighlight)4426{4427TextMenu *tMenu = (TextMenu *)menu;4428int id = tMenu->entryStart[rowID];4429for (int i = 0; i < tMenu->entrySize[rowID]; ++i) {4430DrawBlendedSprite(XPos + (i << 3), YPos, 8, 8, ((tMenu->textData[id] & 0xF) << 3), ((tMenu->textData[id] >> 4) << 3) + textHighlight,4431textMenuSurfaceNo);4432id++;4433}4434}4435void DrawTextMenu(void *menu, int XPos, int YPos)4436{4437TextMenu *tMenu = (TextMenu *)menu;4438int cnt = 0;44394440if (tMenu->visibleRowCount > 0) {4441cnt = (int)(tMenu->visibleRowCount + tMenu->visibleRowOffset);4442}4443else {4444tMenu->visibleRowOffset = 0;4445cnt = (int)tMenu->rowCount;4446}44474448if (tMenu->selectionCount == 3) {4449tMenu->selection2 = -1;4450for (int i = 0; i <= tMenu->selection1; ++i) {4451if (tMenu->entryHighlight[i]) {4452tMenu->selection2 = i;4453}4454}4455}44564457switch (tMenu->alignment) {4458case 0:4459for (int i = (int)tMenu->visibleRowOffset; i < cnt; ++i) {4460switch (tMenu->selectionCount) {4461case 1:4462if (i == tMenu->selection1)4463DrawTextMenuEntry(tMenu, i, XPos, YPos, 128);4464else4465DrawTextMenuEntry(tMenu, i, XPos, YPos, 0);4466break;44674468case 2:4469if (i == tMenu->selection1 || i == tMenu->selection2)4470DrawTextMenuEntry(tMenu, i, XPos, YPos, 128);4471else4472DrawTextMenuEntry(tMenu, i, XPos, YPos, 0);4473break;44744475case 3:4476if (i == tMenu->selection1)4477DrawTextMenuEntry(tMenu, i, XPos, YPos, 128);4478else4479DrawTextMenuEntry(tMenu, i, XPos, YPos, 0);44804481if (i == tMenu->selection2 && i != tMenu->selection1)4482DrawStageTextEntry(tMenu, i, XPos, YPos, 128);4483break;4484}4485YPos += 8;4486}4487break;44884489case 1:4490for (int i = (int)tMenu->visibleRowOffset; i < cnt; ++i) {4491int entryX = XPos - (tMenu->entrySize[i] << 3);4492switch (tMenu->selectionCount) {4493case 1:4494if (i == tMenu->selection1)4495DrawTextMenuEntry(tMenu, i, entryX, YPos, 128);4496else4497DrawTextMenuEntry(tMenu, i, entryX, YPos, 0);4498break;44994500case 2:4501if (i == tMenu->selection1 || i == tMenu->selection2)4502DrawTextMenuEntry(tMenu, i, entryX, YPos, 128);4503else4504DrawTextMenuEntry(tMenu, i, entryX, YPos, 0);4505break;45064507case 3:4508if (i == tMenu->selection1)4509DrawTextMenuEntry(tMenu, i, entryX, YPos, 128);4510else4511DrawTextMenuEntry(tMenu, i, entryX, YPos, 0);45124513if (i == tMenu->selection2 && i != tMenu->selection1)4514DrawStageTextEntry(tMenu, i, entryX, YPos, 128);4515break;4516}4517YPos += 8;4518}4519break;45204521case 2:4522for (int i = (int)tMenu->visibleRowOffset; i < cnt; ++i) {4523int entryX = XPos - (tMenu->entrySize[i] >> 1 << 3);4524switch (tMenu->selectionCount) {4525case 1:4526if (i == tMenu->selection1)4527DrawTextMenuEntry(tMenu, i, entryX, YPos, 128);4528else4529DrawTextMenuEntry(tMenu, i, entryX, YPos, 0);4530break;4531case 2:4532if (i == tMenu->selection1 || i == tMenu->selection2)4533DrawTextMenuEntry(tMenu, i, entryX, YPos, 128);4534else4535DrawTextMenuEntry(tMenu, i, entryX, YPos, 0);4536break;4537case 3:4538if (i == tMenu->selection1)4539DrawTextMenuEntry(tMenu, i, entryX, YPos, 128);4540else4541DrawTextMenuEntry(tMenu, i, entryX, YPos, 0);45424543if (i == tMenu->selection2 && i != tMenu->selection1)4544DrawStageTextEntry(tMenu, i, entryX, YPos, 128);4545break;4546}4547YPos += 8;4548}4549break;45504551default: break;4552}4553}455445554556