Path: blob/master/RSDKv5/RSDK/Graphics/Drawing.cpp
1163 views
#include "RSDK/Core/RetroEngine.hpp"12using namespace RSDK;34#if RETRO_REV0U5#include "Legacy/DrawingLegacy.cpp"6#endif78// all render devices need to access the initial vertex buffer :skull:910// clang-format off11#if RETRO_REV0212const RenderVertex rsdkVertexBuffer[60] = {13// 1 Screen (0)14{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },15{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },16{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },17{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },18{ { 1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },19{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },2021// 2 Screens - Bordered (Top Screen) (6)22{ { -0.5, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },23{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },24{ { 0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },25{ { -0.5, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },26{ { 0.5, 1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },27{ { 0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },2829// 2 Screens - Bordered (Bottom Screen) (12)30{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },31{ { -0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },32{ { 0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },33{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },34{ { 0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },35{ { 0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },3637// 2 Screens - Stretched (Top Screen) (18)38{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },39{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },40{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },41{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },42{ { 1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },43{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },4445// 2 Screens - Stretched (Bottom Screen) (24)46{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },47{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },48{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },49{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },50{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },51{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },5253// 4 Screens (Top-Left) (30)54{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },55{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },56{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },57{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },58{ { 0.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },59{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },6061// 4 Screens (Top-Right) (36)62{ { 0.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },63{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },64{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },65{ { 0.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },66{ { 1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },67{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },6869// 4 Screens (Bottom-Right) (42)70{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },71{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },72{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },73{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },74{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },75{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },7677// 4 Screens (Bottom-Left) (48)78{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },79{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },80{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },81{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },82{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },83{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },8485// Image/Video (54)86{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },87{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },88{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },89{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },90{ { 1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },91{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } }92};93#else94const RenderVertex rsdkVertexBuffer[24] =95{96// 1 Screen (0)97{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },98{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },99{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },100{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },101{ { 1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },102{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },103104// 2 Screens - Stretched (Top Screen) (6)105{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },106{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },107{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },108{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },109{ { 1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },110{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },111112// 2 Screens - Stretched (Bottom Screen) (12)113{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },114{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.9375 } },115{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },116{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },117{ { 1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.0 } },118{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.625, 0.9375 } },119120// Image/Video (18)121{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },122{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },123{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },124{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },125{ { 1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },126{ { 1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } }127};128#endif129// clang-format on130131#if RETRO_RENDERDEVICE_DIRECTX9132#include "DX9/DX9RenderDevice.cpp"133#elif RETRO_RENDERDEVICE_DIRECTX11134#include "DX11/DX11RenderDevice.cpp"135#elif RETRO_RENDERDEVICE_SDL2136#include "SDL2/SDL2RenderDevice.cpp"137#elif RETRO_RENDERDEVICE_GLFW138#include "GLFW/GLFWRenderDevice.cpp"139#elif RETRO_RENDERDEVICE_VK140#include "Vulkan/VulkanRenderDevice.cpp"141#elif RETRO_RENDERDEVICE_EGL142#include "EGL/EGLRenderDevice.cpp"143#endif144145RenderDevice::WindowInfo RenderDevice::displayInfo;146147DrawList RSDK::drawGroups[DRAWGROUP_COUNT];148149uint16 RSDK::blendLookupTable[0x20 * 0x100];150uint16 RSDK::subtractLookupTable[0x20 * 0x100];151152GFXSurface RSDK::gfxSurface[SURFACE_COUNT];153154float RSDK::dpi = 1;155int32 RSDK::cameraCount = 0;156ScreenInfo RSDK::screens[SCREEN_COUNT];157CameraInfo RSDK::cameras[CAMERA_COUNT];158ScreenInfo *RSDK::currentScreen = NULL;159160int32 RSDK::shaderCount = 0;161ShaderEntry RSDK::shaderList[SHADER_COUNT];162163bool32 RSDK::changedVideoSettings = false;164VideoSettings RSDK::videoSettings;165VideoSettings RSDK::videoSettingsBackup;166167#if RETRO_USE_MOD_LOADER168int32 RSDK::userShaderCount = 0;169#endif170171bool32 RenderDeviceBase::isRunning = false;172int32 RenderDeviceBase::windowRefreshDelay = 0;173174#if RETRO_REV02175uint8 RenderDeviceBase::startVertex_2P[] = { 18, 24 };176uint8 RenderDeviceBase::startVertex_3P[] = { 30, 36, 12 };177#endif178179float2 RenderDeviceBase::pixelSize = { DEFAULT_PIXWIDTH, SCREEN_YSIZE };180float2 RenderDeviceBase::textureSize = { 512.0, 256.0 };181float2 RenderDeviceBase::viewSize = { 0, 0 };182183int32 RenderDeviceBase::displayWidth[16];184int32 RenderDeviceBase::displayHeight[16];185int32 RenderDeviceBase::displayCount = 0;186187int32 RenderDeviceBase::lastShaderID = -1;188189char RSDK::drawGroupNames[0x10][0x10] = {190"Draw Group 0", "Draw Group 1", "Draw Group 2", "Draw Group 3", "Draw Group 4", "Draw Group 5", "Draw Group 6", "Draw Group 7",191"Draw Group 8", "Draw Group 9", "Draw Group 10", "Draw Group 11", "Draw Group 12", "Draw Group 13", "Draw Group 14", "Draw Group 15",192};193194#include "RSDK/Dev/DevFont.hpp"195196// 50% alpha, but way faster197#define setPixelBlend(pixel, frameBufferClr) frameBufferClr = ((pixel >> 1) & 0x7BEF) + ((frameBufferClr >> 1) & 0x7BEF)198199// Alpha blending200#define setPixelAlpha(pixel, frameBufferClr, alpha) \201int32 R = (fbufferBlend[(frameBufferClr & 0xF800) >> 11] + pixelBlend[(pixel & 0xF800) >> 11]) << 11; \202int32 G = (fbufferBlend[(frameBufferClr & 0x7E0) >> 6] + pixelBlend[(pixel & 0x7E0) >> 6]) << 6; \203int32 B = fbufferBlend[frameBufferClr & 0x1F] + pixelBlend[pixel & 0x1F]; \204\205frameBufferClr = R | G | B;206207// Additive Blending208#define setPixelAdditive(pixel, frameBufferClr) \209int32 R = MIN((blendTablePtr[(pixel & 0xF800) >> 11] << 11) + (frameBufferClr & 0xF800), 0xF800); \210int32 G = MIN((blendTablePtr[(pixel & 0x7E0) >> 6] << 6) + (frameBufferClr & 0x7E0), 0x7E0); \211int32 B = MIN(blendTablePtr[pixel & 0x1F] + (frameBufferClr & 0x1F), 0x1F); \212\213frameBufferClr = R | G | B;214215// Subtractive Blending216#define setPixelSubtractive(pixel, frameBufferClr) \217int32 R = MAX((frameBufferClr & 0xF800) - (subBlendTable[(pixel & 0xF800) >> 11] << 11), 0); \218int32 G = MAX((frameBufferClr & 0x7E0) - (subBlendTable[(pixel & 0x7E0) >> 6] << 6), 0); \219int32 B = MAX((frameBufferClr & 0x1F) - subBlendTable[pixel & 0x1F], 0); \220\221frameBufferClr = R | G | B;222223// Only draw if framebuffer clr IS maskColor224#define setPixelMasked(pixel, frameBufferClr) \225if (frameBufferClr == maskColor) \226frameBufferClr = pixel;227228// Only draw if framebuffer clr is NOT maskColor229#define setPixelUnmasked(pixel, frameBufferClr) \230if (frameBufferClr != maskColor) \231frameBufferClr = pixel;232233void RSDK::RenderDeviceBase::ProcessDimming()234{235// Bug Details:236// if you've ever used debug mode before the first frame of v5 executes you may've seen how the game starts dimmed237// this is because dimLimit hasn't been initialized yet, so it starts at 0. Likewise, the timer also starts at 0238// this leads the game to immediately begin dimming when it shouldn't be239// Fix:240// initialize dimLimit before ProcessStage(), maybe in RenderDevice::SetupRendering() or something241242if (videoSettings.dimTimer < videoSettings.dimLimit) {243if (videoSettings.dimPercent < 1.0f) {244videoSettings.dimPercent += 0.05f;245246if (videoSettings.dimPercent > 1.0f)247videoSettings.dimPercent = 1.0f;248}249}250else {251if (videoSettings.dimPercent > 0.25f)252videoSettings.dimPercent *= 0.9f;253}254}255256void RSDK::GenerateBlendLookupTable()257{258for (int32 y = 0; y < 0x100; y++) {259for (int32 x = 0; x < 0x20; x++) {260blendLookupTable[x + (y * 0x20)] = y * x >> 8;261subtractLookupTable[x + (y * 0x20)] = y * (0x1F - x) >> 8;262}263}264265#if !RETRO_REV02266for (int32 i = 0; i < 0x10000; ++i) {267int32 tintValue = (((uint32)i & 0x1F) + ((i >> 6) & 0x1F) + (((uint16)i >> 11) & 0x1F)) / 3 + 6;268tintLookupTable[i] = 0x841 * MIN(0x1F, tintValue);269}270#endif271272for (int32 c = 0; c < 0x100; ++c) {273rgb32To16_R[c] = (c & 0xFFF8) << 8;274rgb32To16_G[c] = (c & 0xFFFC) << 3;275rgb32To16_B[c] = c >> 3;276}277}278279void RSDK::InitSystemSurfaces()280{281GEN_HASH_MD5("TileBuffer", gfxSurface[0].hash);282gfxSurface[0].scope = SCOPE_GLOBAL;283gfxSurface[0].width = TILE_SIZE;284gfxSurface[0].height = TILE_COUNT * TILE_SIZE;285gfxSurface[0].lineSize = 4; // 16px286gfxSurface[0].pixels = tilesetPixels;287288#if RETRO_REV02289GEN_HASH_MD5("EngineText", gfxSurface[1].hash);290gfxSurface[1].scope = SCOPE_GLOBAL;291gfxSurface[1].width = 8;292gfxSurface[1].height = 128 * 8;293gfxSurface[1].lineSize = 3; // 8px294gfxSurface[1].pixels = devTextStencil;295#endif296}297298void RSDK::UpdateGameWindow() { RenderDevice::RefreshWindow(); }299300void RSDK::GetDisplayInfo(int32 *displayID, int32 *width, int32 *height, int32 *refreshRate, char *text)301{302if (!displayID)303return;304305int32 prevDisplay = *displayID;306int32 display = 0;307308if (*displayID == -2) { // -2 == "get FS size display"309if (videoSettings.fsWidth && videoSettings.fsHeight) {310for (display = 0; display < RenderDevice::displayCount; ++display) {311#if RETRO_RENDERDEVICE_DIRECTX11312int32 refresh = RenderDevice::displayInfo.displays[display].refresh_rate.Numerator313/ RenderDevice::displayInfo.displays[display].refresh_rate.Denominator;314#else315int32 refresh = RenderDevice::displayInfo.displays[display].refresh_rate;316#endif317318if (RenderDevice::displayInfo.displays[display].width == videoSettings.fsWidth319&& RenderDevice::displayInfo.displays[display].height == videoSettings.fsHeight && refresh == videoSettings.refreshRate) {320break;321}322}323324display++;325}326}327else {328display = *displayID;329if (prevDisplay < 0)330display = RenderDevice::displayCount;331else if (prevDisplay > RenderDevice::displayCount)332display = 0;333}334335*displayID = display;336if (display) {337int32 d = display - 1;338339#if RETRO_RENDERDEVICE_DIRECTX11340int32 refresh = RenderDevice::displayInfo.displays[d].refresh_rate.Numerator / RenderDevice::displayInfo.displays[d].refresh_rate.Denominator;341#else342int32 refresh = RenderDevice::displayInfo.displays[d].refresh_rate;343#endif344345int32 displayWidth = RenderDevice::displayInfo.displays[d].width;346int32 displayHeight = RenderDevice::displayInfo.displays[d].height;347int32 displayRefresh = refresh;348349if (width)350*width = displayWidth;351352if (height)353*height = displayHeight;354355if (refreshRate)356*refreshRate = displayRefresh;357358if (text)359sprintf(text, "%ix%i @%iHz", displayWidth, displayHeight, displayRefresh);360}361else { // displayID 0 == "default fullscreen size"362if (width)363*width = 0;364365if (height)366*height = 0;367368if (refreshRate)369*refreshRate = 0;370371if (text)372sprintf(text, "%s", "DEFAULT");373}374}375376void RSDK::GetWindowSize(int32 *width, int32 *height) { RenderDevice::GetWindowSize(width, height); }377378void RSDK::SetScreenSize(uint8 screenID, uint16 width, uint16 height)379{380if (screenID < SCREEN_COUNT) {381ScreenInfo *screen = &screens[screenID];382383screen->size.x = width;384screen->size.y = height & 0xFFF0;385screen->pitch = (screen->size.x + 15) & 0xFFFFFFF0;386screen->center.x = screen->size.x >> 1;387screen->center.y = screen->size.y >> 1;388389screen->clipBound_X1 = 0;390screen->clipBound_X2 = screen->size.x;391screen->clipBound_Y1 = 0;392screen->clipBound_Y2 = screen->size.y;393394screen->waterDrawPos = screen->size.y;395396#if RETRO_REV0U397RSDK::Legacy::SCREEN_XSIZE = width;398RSDK::Legacy::SCREEN_CENTERX = width / 2;399RSDK::Legacy::SCREEN_SCROLL_LEFT = RSDK::Legacy::SCREEN_CENTERX - 8;400RSDK::Legacy::SCREEN_SCROLL_RIGHT = RSDK::Legacy::SCREEN_CENTERX + 8;401RSDK::Legacy::OBJECT_BORDER_X2 = width + 0x80;402RSDK::Legacy::OBJECT_BORDER_X4 = width + 0x20;403404RSDK::Legacy::GFX_LINESIZE = screen->pitch;405RSDK::Legacy::GFX_LINESIZE_MINUSONE = screen->pitch - 1;406RSDK::Legacy::GFX_LINESIZE_DOUBLE = 2 * screen->pitch;407RSDK::Legacy::GFX_FRAMEBUFFERSIZE = SCREEN_YSIZE * screen->pitch;408RSDK::Legacy::GFX_FBUFFERMINUSONE = SCREEN_YSIZE * screen->pitch - 1;409#endif410}411}412413int32 RSDK::GetVideoSetting(int32 id)414{415switch (id) {416case VIDEOSETTING_WINDOWED: return videoSettings.windowed;417case VIDEOSETTING_BORDERED: return videoSettings.bordered;418case VIDEOSETTING_EXCLUSIVEFS: return videoSettings.exclusiveFS;419case VIDEOSETTING_VSYNC: return videoSettings.vsync;420case VIDEOSETTING_TRIPLEBUFFERED: return videoSettings.tripleBuffered;421case VIDEOSETTING_WINDOW_WIDTH: return videoSettings.windowWidth;422case VIDEOSETTING_WINDOW_HEIGHT: return videoSettings.windowHeight;423case VIDEOSETTING_FSWIDTH: return videoSettings.fsWidth;424case VIDEOSETTING_FSHEIGHT: return videoSettings.fsHeight;425case VIDEOSETTING_REFRESHRATE: return videoSettings.refreshRate;426case VIDEOSETTING_SHADERSUPPORT: return videoSettings.shaderSupport;427case VIDEOSETTING_SHADERID: return videoSettings.shaderID;428case VIDEOSETTING_SCREENCOUNT: return videoSettings.screenCount;429#if RETRO_REV02430case VIDEOSETTING_DIMTIMER: return videoSettings.dimTimer;431#endif432case VIDEOSETTING_STREAMSENABLED: return engine.streamsEnabled;433case VIDEOSETTING_STREAM_VOL: return (int32)(engine.streamVolume * 1024.0);434case VIDEOSETTING_SFX_VOL: return (int32)(engine.soundFXVolume * 1024.0);435case VIDEOSETTING_LANGUAGE:436#if RETRO_REV02437return SKU::curSKU.language;438#else439return gameVerInfo.language;440#endif441case VIDEOSETTING_CHANGED: return changedVideoSettings;442443default: break;444}445446return 0;447}448449void RSDK::SetVideoSetting(int32 id, int32 value)450{451bool32 boolVal = value;452switch (id) {453case VIDEOSETTING_WINDOWED:454if (videoSettings.windowed != boolVal) {455videoSettings.windowed = boolVal;456changedVideoSettings = true;457}458break;459460case VIDEOSETTING_BORDERED:461if (videoSettings.bordered != boolVal) {462videoSettings.bordered = boolVal;463changedVideoSettings = true;464}465break;466467case VIDEOSETTING_EXCLUSIVEFS:468if (videoSettings.exclusiveFS != boolVal) {469videoSettings.exclusiveFS = boolVal;470changedVideoSettings = true;471}472break;473474case VIDEOSETTING_VSYNC:475if (videoSettings.vsync != boolVal) {476videoSettings.vsync = boolVal;477changedVideoSettings = true;478}479break;480481case VIDEOSETTING_TRIPLEBUFFERED:482if (videoSettings.tripleBuffered != boolVal) {483videoSettings.tripleBuffered = boolVal;484changedVideoSettings = true;485}486break;487488case VIDEOSETTING_WINDOW_WIDTH:489if (videoSettings.windowWidth != value) {490videoSettings.windowWidth = value;491changedVideoSettings = true;492}493break;494495case VIDEOSETTING_WINDOW_HEIGHT:496if (videoSettings.windowHeight != value) {497videoSettings.windowHeight = value;498changedVideoSettings = true;499}500break;501502case VIDEOSETTING_FSWIDTH: videoSettings.fsWidth = value; break;503case VIDEOSETTING_FSHEIGHT: videoSettings.fsHeight = value; break;504case VIDEOSETTING_REFRESHRATE: videoSettings.refreshRate = value; break;505case VIDEOSETTING_SHADERSUPPORT: videoSettings.shaderSupport = value; break;506case VIDEOSETTING_SHADERID:507if (videoSettings.shaderID != value) {508videoSettings.shaderID = value;509changedVideoSettings = true;510}511break;512513case VIDEOSETTING_SCREENCOUNT: videoSettings.screenCount = value; break;514#if RETRO_REV02515case VIDEOSETTING_DIMTIMER: videoSettings.dimLimit = value; break;516#endif517case VIDEOSETTING_STREAMSENABLED:518if (engine.streamsEnabled != boolVal)519changedVideoSettings = true;520521engine.streamsEnabled = boolVal;522break;523524case VIDEOSETTING_STREAM_VOL:525if (engine.streamVolume != (value / 1024.0f)) {526engine.streamVolume = (float)value / 1024.0f;527changedVideoSettings = true;528}529break;530531case VIDEOSETTING_SFX_VOL:532if (engine.soundFXVolume != ((float)value / 1024.0f)) {533engine.soundFXVolume = (float)value / 1024.0f;534changedVideoSettings = true;535}536break;537538case VIDEOSETTING_LANGUAGE:539#if RETRO_REV02540SKU::curSKU.language = value;541#else542gameVerInfo.language = value;543#endif544break;545546case VIDEOSETTING_STORE: memcpy(&videoSettingsBackup, &videoSettings, sizeof(videoSettings)); break;547548case VIDEOSETTING_RELOAD:549changedVideoSettings = true;550memcpy(&videoSettings, &videoSettingsBackup, sizeof(videoSettingsBackup));551break;552553case VIDEOSETTING_CHANGED: changedVideoSettings = boolVal; break;554555case VIDEOSETTING_WRITE: SaveSettingsINI(value); break;556557default: break;558}559}560561void RSDK::SwapDrawListEntries(uint8 drawGroup, uint16 slot1, uint16 slot2, uint16 count)562{563if (drawGroup < DRAWGROUP_COUNT) {564DrawList *group = &drawGroups[drawGroup];565if (count <= 0 || count > group->entityCount)566count = group->entityCount;567568int32 index1 = -1;569int32 index2 = -1;570for (int32 i = 0; i < count; ++i) {571if (group->entries[i] == slot1)572index1 = i;573if (group->entries[i] == slot2)574index2 = i;575}576577if (index1 > -1 && index2 > -1 && index1 < index2) {578int32 temp = group->entries[index2];579group->entries[index2] = group->entries[index1];580group->entries[index1] = temp;581}582}583}584585void RSDK::FillScreen(uint32 color, int32 alphaR, int32 alphaG, int32 alphaB)586{587alphaR = CLAMP(alphaR, 0x00, 0xFF);588alphaG = CLAMP(alphaG, 0x00, 0xFF);589alphaB = CLAMP(alphaB, 0x00, 0xFF);590591if (alphaR + alphaG + alphaB) {592validDraw = true;593uint16 clrBlendR = blendLookupTable[0x20 * alphaR + rgb32To16_B[(color >> 0x10) & 0xFF]];594uint16 clrBlendG = blendLookupTable[0x20 * alphaG + rgb32To16_B[(color >> 0x08) & 0xFF]];595uint16 clrBlendB = blendLookupTable[0x20 * alphaB + rgb32To16_B[(color >> 0x00) & 0xFF]];596597uint16 *fbBlendR = &blendLookupTable[0x20 * (0xFF - alphaR)];598uint16 *fbBlendG = &blendLookupTable[0x20 * (0xFF - alphaG)];599uint16 *fbBlendB = &blendLookupTable[0x20 * (0xFF - alphaB)];600601int32 cnt = currentScreen->size.y * currentScreen->pitch;602for (int32 id = 0; cnt > 0; --cnt, ++id) {603uint16 px = currentScreen->frameBuffer[id];604605int32 R = fbBlendR[(px & 0xF800) >> 11] + clrBlendR;606int32 G = fbBlendG[(px & 0x7E0) >> 6] + clrBlendG;607int32 B = fbBlendB[px & 0x1F] + clrBlendB;608609currentScreen->frameBuffer[id] = (B) | (G << 6) | (R << 11);610}611}612}613614void RSDK::DrawLine(int32 x1, int32 y1, int32 x2, int32 y2, uint32 color, int32 alpha, int32 inkEffect, bool32 screenRelative)615{616switch (inkEffect) {617default: break;618619case INK_ALPHA:620if (alpha > 0xFF)621inkEffect = INK_NONE;622else if (alpha <= 0)623return;624break;625626case INK_ADD:627case INK_SUB:628if (alpha > 0xFF)629alpha = 0xFF;630else if (alpha <= 0)631return;632break;633634case INK_TINT:635if (!tintLookupTable)636return;637break;638}639640int32 drawY1 = y1;641int32 drawX1 = x1;642int32 drawY2 = y2;643int32 drawX2 = x2;644645if (!screenRelative) {646drawX1 = FROM_FIXED(x1) - currentScreen->position.x;647drawY1 = FROM_FIXED(y1) - currentScreen->position.y;648drawX2 = FROM_FIXED(x2) - currentScreen->position.x;649drawY2 = FROM_FIXED(y2) - currentScreen->position.y;650}651652int32 flags1 = 0;653if (drawX1 >= currentScreen->clipBound_X2)654flags1 = 2;655else if (drawX1 < currentScreen->clipBound_X1)656flags1 = 1;657658if (drawY1 >= currentScreen->clipBound_Y2)659flags1 |= 8;660else if (drawY1 < currentScreen->clipBound_Y1)661flags1 |= 4;662663int32 flags2 = 0;664if (drawX2 >= currentScreen->clipBound_X2)665flags2 = 2;666else if (drawX2 < currentScreen->clipBound_X1)667flags2 = 1;668669if (drawY2 >= currentScreen->clipBound_Y2)670flags2 |= 8;671else if (drawY2 < currentScreen->clipBound_Y1)672flags2 |= 4;673674while (flags1 || flags2) {675if (flags1 & flags2)676return;677678int32 curFlags = flags2;679if (flags1)680curFlags = flags1;681682int32 x = 0;683int32 y = 0;684if (curFlags & 8) {685int32 div = (drawY2 - drawY1);686if (!div)687div = 1;688x = drawX1 + ((drawX2 - drawX1) * (((currentScreen->clipBound_Y2 - drawY1) << 8) / div) >> 8);689y = currentScreen->clipBound_Y2;690}691else if (curFlags & 4) {692int32 div = (drawY2 - drawY1);693if (!div)694div = 1;695x = drawX1 + ((drawX2 - drawX1) * (((currentScreen->clipBound_Y1 - drawY1) << 8) / div) >> 8);696y = currentScreen->clipBound_Y1;697}698else if (curFlags & 2) {699int32 div = (drawX2 - drawX1);700if (!div)701div = 1;702x = currentScreen->clipBound_X2;703y = drawY1 + ((drawY2 - drawY1) * (((currentScreen->clipBound_X2 - drawX1) << 8) / div) >> 8);704}705else if (curFlags & 1) {706int32 div = (drawX2 - drawX1);707if (!div)708div = 1;709x = currentScreen->clipBound_X1;710y = drawY1 + ((drawY2 - drawY1) * (((currentScreen->clipBound_X1 - drawX1) << 8) / div) >> 8);711}712713if (curFlags == flags1) {714drawX1 = x;715drawY1 = y;716flags1 = 0;717if (x > currentScreen->clipBound_X2) {718flags1 = 2;719}720else if (x < currentScreen->clipBound_X1) {721flags1 = 1;722}723724if (y < currentScreen->clipBound_Y1) {725flags1 |= 4;726}727else if (y > currentScreen->clipBound_Y2) {728flags1 |= 8;729}730}731else {732drawX2 = x;733drawY2 = y;734flags2 = 0;735if (x > currentScreen->clipBound_X2) {736flags2 = 2;737}738else if (x < currentScreen->clipBound_X1) {739flags2 = 1;740}741742if (y < currentScreen->clipBound_Y1) {743flags2 |= 4;744}745else if (y > currentScreen->clipBound_Y2) {746flags2 |= 8;747}748}749}750751if (drawX1 > currentScreen->clipBound_X2)752drawX1 = currentScreen->clipBound_X2;753else if (drawX1 < currentScreen->clipBound_X1)754drawX1 = currentScreen->clipBound_X1;755756if (drawY1 > currentScreen->clipBound_Y2)757drawY1 = currentScreen->clipBound_Y2;758else if (drawY1 < currentScreen->clipBound_Y1)759drawY1 = currentScreen->clipBound_Y1;760761if (drawX2 > currentScreen->clipBound_X2)762drawX2 = currentScreen->clipBound_X2;763else if (drawX2 < currentScreen->clipBound_X1)764drawX2 = currentScreen->clipBound_X1;765766if (drawY2 > currentScreen->clipBound_Y2)767drawY2 = currentScreen->clipBound_Y2;768else if (drawY2 < currentScreen->clipBound_Y1)769drawY2 = currentScreen->clipBound_Y1;770771int32 sizeX = abs(drawX2 - drawX1);772int32 sizeY = abs(drawY2 - drawY1);773int32 max = sizeY;774int32 hSize = sizeX >> 2;775if (sizeX <= sizeY)776hSize = -sizeY >> 2;777778if (drawX2 < drawX1) {779int32 v = drawX1;780drawX1 = drawX2;781drawX2 = v;782783v = drawY1;784drawY1 = drawY2;785drawY2 = v;786}787788uint16 color16 = rgb32To16_B[(color >> 0) & 0xFF] | rgb32To16_G[(color >> 8) & 0xFF] | rgb32To16_R[(color >> 16) & 0xFF];789uint16 *frameBuffer = ¤tScreen->frameBuffer[drawX1 + drawY1 * currentScreen->pitch];790791switch (inkEffect) {792case INK_NONE:793if (drawY1 > drawY2) {794while (drawX1 < drawX2 || drawY1 >= drawY2) {795*frameBuffer = color16;796797if (hSize > -sizeX) {798hSize -= max;799++drawX1;800++frameBuffer;801}802803if (hSize < max) {804--drawY1;805hSize += sizeX;806frameBuffer -= currentScreen->pitch;807}808}809}810else {811while (true) {812*frameBuffer = color16;813814if (drawX1 < drawX2 || drawY1 < drawY2) {815if (hSize > -sizeX) {816hSize -= max;817++drawX1;818++frameBuffer;819}820821if (hSize < max) {822hSize += sizeX;823++drawY1;824frameBuffer += currentScreen->pitch;825}826}827else {828break;829}830}831}832break;833834case INK_BLEND:835if (drawY1 > drawY2) {836while (drawX1 < drawX2 || drawY1 >= drawY2) {837setPixelBlend(color16, *frameBuffer);838839if (hSize > -sizeX) {840hSize -= max;841++drawX1;842++frameBuffer;843}844845if (hSize < max) {846--drawY1;847hSize += sizeX;848frameBuffer -= currentScreen->pitch;849}850}851}852else {853while (true) {854setPixelBlend(color16, *frameBuffer);855856if (drawX1 < drawX2 || drawY1 < drawY2) {857if (hSize > -sizeX) {858hSize -= max;859++drawX1;860++frameBuffer;861}862863if (hSize < max) {864hSize += sizeX;865++drawY1;866frameBuffer += currentScreen->pitch;867}868}869else {870break;871}872}873}874break;875876case INK_ALPHA:877if (drawY1 > drawY2) {878uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];879uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];880881while (drawX1 < drawX2 || drawY1 >= drawY2) {882setPixelAlpha(color16, *frameBuffer, alpha);883884if (hSize > -sizeX) {885hSize -= max;886++drawX1;887++frameBuffer;888}889890if (hSize < max) {891--drawY1;892hSize += sizeX;893frameBuffer -= currentScreen->pitch;894}895}896}897else {898uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];899uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];900901while (true) {902setPixelAlpha(color16, *frameBuffer, alpha);903904if (drawX1 < drawX2 || drawY1 < drawY2) {905if (hSize > -sizeX) {906hSize -= max;907++drawX1;908++frameBuffer;909}910if (hSize < max) {911hSize += sizeX;912++drawY1;913frameBuffer += currentScreen->pitch;914}915}916else {917break;918}919}920}921break;922923case INK_ADD:924if (drawY1 > drawY2) {925uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];926927while (drawX1 < drawX2 || drawY1 >= drawY2) {928setPixelAdditive(color16, *frameBuffer);929930if (hSize > -sizeX) {931hSize -= max;932++drawX1;933++frameBuffer;934}935936if (hSize < max) {937--drawY1;938hSize += sizeX;939frameBuffer -= currentScreen->pitch;940}941}942}943else {944uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];945946while (true) {947setPixelAdditive(color16, *frameBuffer);948if (drawX1 < drawX2 || drawY1 < drawY2) {949if (hSize > -sizeX) {950hSize -= max;951++drawX1;952++frameBuffer;953}954955if (hSize < max) {956hSize += sizeX;957++drawY1;958frameBuffer += currentScreen->pitch;959}960}961else {962break;963}964}965}966break;967968case INK_SUB:969if (drawY1 > drawY2) {970uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];971while (drawX1 < drawX2 || drawY1 >= drawY2) {972setPixelSubtractive(color16, *frameBuffer);973974if (hSize > -sizeX) {975hSize -= max;976++drawX1;977++frameBuffer;978}979980if (hSize < max) {981--drawY1;982hSize += sizeX;983frameBuffer -= currentScreen->pitch;984}985}986}987else {988uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];989while (true) {990setPixelSubtractive(color16, *frameBuffer);991992if (drawX1 < drawX2 || drawY1 < drawY2) {993if (hSize > -sizeX) {994hSize -= max;995++drawX1;996++frameBuffer;997}998999if (hSize < max) {1000hSize += sizeX;1001++drawY1;1002frameBuffer += currentScreen->pitch;1003}1004}1005else {1006break;1007}1008}1009}1010break;10111012case INK_TINT:1013if (drawY1 > drawY2) {1014while (drawX1 < drawX2 || drawY1 >= drawY2) {1015*frameBuffer = tintLookupTable[*frameBuffer];10161017if (hSize > -sizeX) {1018hSize -= max;1019++drawX1;1020++frameBuffer;1021}10221023if (hSize < max) {1024--drawY1;1025hSize += sizeX;1026frameBuffer -= currentScreen->pitch;1027}1028}1029}1030else {1031while (true) {1032*frameBuffer = tintLookupTable[*frameBuffer];10331034if (drawX1 < drawX2 || drawY1 < drawY2) {1035if (hSize > -sizeX) {1036hSize -= max;1037++drawX1;1038++frameBuffer;1039}10401041if (hSize < max) {1042hSize += sizeX;1043++drawY1;1044frameBuffer += currentScreen->pitch;1045}1046}1047else {1048break;1049}1050}1051}1052break;10531054case INK_MASKED:1055if (drawY1 > drawY2) {1056while (drawX1 < drawX2 || drawY1 >= drawY2) {1057if (*frameBuffer == maskColor)1058*frameBuffer = color16;10591060if (hSize > -sizeX) {1061hSize -= max;1062++drawX1;1063++frameBuffer;1064}10651066if (hSize < max) {1067--drawY1;1068hSize += sizeX;1069frameBuffer -= currentScreen->pitch;1070}1071}1072}1073else {1074while (true) {1075if (*frameBuffer == maskColor)1076*frameBuffer = color16;10771078if (drawX1 < drawX2 || drawY1 < drawY2) {1079if (hSize > -sizeX) {1080hSize -= max;1081++drawX1;1082++frameBuffer;1083}10841085if (hSize < max) {1086hSize += sizeX;1087++drawY1;1088frameBuffer += currentScreen->pitch;1089}1090}1091else {1092break;1093}1094}1095}1096break;10971098case INK_UNMASKED:1099if (drawY1 > drawY2) {1100while (drawX1 < drawX2 || drawY1 >= drawY2) {1101if (*frameBuffer != maskColor)1102*frameBuffer = color16;11031104if (hSize > -sizeX) {1105hSize -= max;1106++drawX1;1107++frameBuffer;1108}11091110if (hSize < max) {1111--drawY1;1112hSize += sizeX;1113frameBuffer -= currentScreen->pitch;1114}1115}1116}1117else {1118while (true) {1119if (*frameBuffer != maskColor)1120*frameBuffer = color16;11211122if (drawX1 < drawX2 || drawY1 < drawY2) {1123if (hSize > -sizeX) {1124hSize -= max;1125++drawX1;1126++frameBuffer;1127}11281129if (hSize < max) {1130hSize += sizeX;1131++drawY1;1132frameBuffer += currentScreen->pitch;1133}1134}1135else {1136break;1137}1138}1139}1140break;1141}1142}1143void RSDK::DrawRectangle(int32 x, int32 y, int32 width, int32 height, uint32 color, int32 alpha, int32 inkEffect, bool32 screenRelative)1144{1145switch (inkEffect) {1146default: break;1147case INK_ALPHA:1148if (alpha > 0xFF)1149inkEffect = INK_NONE;1150else if (alpha <= 0)1151return;1152break;11531154case INK_ADD:1155case INK_SUB:1156if (alpha > 0xFF)1157alpha = 0xFF;1158else if (alpha <= 0)1159return;1160break;11611162case INK_TINT:1163if (!tintLookupTable)1164return;1165break;1166}11671168if (!screenRelative) {1169x = FROM_FIXED(x) - currentScreen->position.x;1170y = FROM_FIXED(y) - currentScreen->position.y;1171width = FROM_FIXED(width);1172height = FROM_FIXED(height);1173}11741175if (width + x > currentScreen->clipBound_X2)1176width = currentScreen->clipBound_X2 - x;11771178if (x < currentScreen->clipBound_X1) {1179width += x - currentScreen->clipBound_X1;1180x = currentScreen->clipBound_X1;1181}11821183if (height + y > currentScreen->clipBound_Y2)1184height = currentScreen->clipBound_Y2 - y;11851186if (y < currentScreen->clipBound_Y1) {1187height += y - currentScreen->clipBound_Y1;1188y = currentScreen->clipBound_Y1;1189}11901191if (width <= 0 || height <= 0)1192return;11931194int32 pitch = currentScreen->pitch - width;1195validDraw = true;1196uint16 *frameBuffer = ¤tScreen->frameBuffer[x + (y * currentScreen->pitch)];1197uint16 color16 = rgb32To16_B[(color >> 0) & 0xFF] | rgb32To16_G[(color >> 8) & 0xFF] | rgb32To16_R[(color >> 16) & 0xFF];11981199switch (inkEffect) {1200case INK_NONE: {1201int32 h = height;1202while (h--) {1203int32 w = width;1204while (w--) {1205*frameBuffer = color16;1206++frameBuffer;1207}12081209frameBuffer += pitch;1210}1211break;1212}12131214case INK_BLEND: {1215int32 h = height;1216while (h--) {1217int32 w = width;1218while (w--) {1219setPixelBlend(color16, *frameBuffer);1220++frameBuffer;1221}1222frameBuffer += pitch;1223}1224break;1225}12261227case INK_ALPHA: {1228uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];1229uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];12301231int32 h = height;1232while (h--) {1233int32 w = width;1234while (w--) {1235setPixelAlpha(color16, *frameBuffer, alpha);1236++frameBuffer;1237}1238frameBuffer += pitch;1239}1240break;1241}12421243case INK_ADD: {1244uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];1245int32 h = height;1246while (h--) {1247int32 w = width;1248while (w--) {1249setPixelAdditive(color16, *frameBuffer);1250++frameBuffer;1251}1252frameBuffer += pitch;1253}1254break;1255}12561257case INK_SUB: {1258uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];1259int32 h = height;1260while (h--) {1261int32 w = width;1262while (w--) {1263setPixelSubtractive(color16, *frameBuffer);1264++frameBuffer;1265}1266frameBuffer += pitch;1267}1268break;1269}12701271case INK_TINT: {1272int32 h = height;1273while (h--) {1274int32 w = width;1275while (w--) {1276*frameBuffer = tintLookupTable[*frameBuffer];1277++frameBuffer;1278}1279frameBuffer += pitch;1280}1281break;1282}12831284case INK_MASKED: {1285int32 h = height;1286while (h--) {1287int32 w = width;1288while (w--) {1289if (*frameBuffer == maskColor)1290*frameBuffer = color16;1291++frameBuffer;1292}1293frameBuffer += pitch;1294}1295break;1296}12971298case INK_UNMASKED: {1299int32 h = height;1300while (h--) {1301int32 w = width;1302while (w--) {1303if (*frameBuffer != maskColor)1304*frameBuffer = color16;1305++frameBuffer;1306}1307frameBuffer += pitch;1308}1309break;1310}1311}1312}1313void RSDK::DrawCircle(int32 x, int32 y, int32 radius, uint32 color, int32 alpha, int32 inkEffect, bool32 screenRelative)1314{1315if (radius > 0) {1316switch (inkEffect) {1317default: break;1318case INK_ALPHA:1319if (alpha > 0xFF)1320inkEffect = INK_NONE;1321else if (alpha <= 0)1322return;1323break;13241325case INK_ADD:1326case INK_SUB:1327if (alpha > 0xFF)1328alpha = 0xFF;1329else if (alpha <= 0)1330return;1331break;13321333case INK_TINT:1334if (!tintLookupTable)1335return;1336break;1337}13381339if (!screenRelative) {1340x = FROM_FIXED(x) - currentScreen->position.x;1341y = FROM_FIXED(y) - currentScreen->position.y;1342}13431344int32 yRadiusBottom = y + radius;1345int32 bottom = yRadiusBottom + 1;1346int32 yRadiusTop = y - radius;1347int32 top = yRadiusTop;13481349if (top < currentScreen->clipBound_Y1)1350top = currentScreen->clipBound_Y1;1351else if (top > currentScreen->clipBound_Y2)1352top = currentScreen->clipBound_Y2;13531354if (bottom < currentScreen->clipBound_Y1)1355bottom = currentScreen->clipBound_Y1;1356else if (bottom > currentScreen->clipBound_Y2)1357bottom = currentScreen->clipBound_Y2;13581359if (top != bottom) {1360for (int32 i = top; i < bottom; ++i) {1361scanEdgeBuffer[i].start = 0x7FFF;1362scanEdgeBuffer[i].end = -1;1363}13641365int32 r = 3 - 2 * radius;1366int32 xRad = x - radius;1367int32 curY = y;1368int32 curX = x;1369int32 dist = x - y;13701371for (int32 i = 0; i <= radius; ++i) {1372int32 scanX = i + curX;13731374if (yRadiusBottom >= top && yRadiusBottom <= bottom && scanX > scanEdgeBuffer[yRadiusBottom].end)1375scanEdgeBuffer[yRadiusBottom].end = scanX;13761377if (yRadiusTop >= top && yRadiusTop <= bottom && scanX > scanEdgeBuffer[yRadiusTop].end)1378scanEdgeBuffer[yRadiusTop].end = scanX;13791380int32 scanY = i + y;1381if (scanY >= top && scanY <= bottom) {1382ScanEdge *edge = &scanEdgeBuffer[scanY];1383if (yRadiusBottom + dist > edge->end)1384edge->end = yRadiusBottom + dist;1385}13861387if (curY >= top && curY <= bottom && yRadiusBottom + dist > scanEdgeBuffer[curY].end)1388scanEdgeBuffer[curY].end = yRadiusBottom + dist;13891390if (yRadiusBottom >= top && yRadiusBottom <= bottom && x < scanEdgeBuffer[yRadiusBottom].start)1391scanEdgeBuffer[yRadiusBottom].start = x;13921393if (yRadiusTop >= top && yRadiusTop <= bottom && x < scanEdgeBuffer[yRadiusTop].start)1394scanEdgeBuffer[yRadiusTop].start = x;13951396if (scanY >= top && scanY <= bottom) {1397ScanEdge *edge = &scanEdgeBuffer[scanY];1398if (xRad < edge->start)1399edge->start = xRad;1400}14011402if (curY >= top && curY <= bottom && xRad < scanEdgeBuffer[curY].start)1403scanEdgeBuffer[curY].start = xRad;14041405if (r >= 0) {1406--yRadiusBottom;1407++yRadiusTop;1408r += 4 * (i - radius) + 10;1409--radius;1410++xRad;1411}1412else {1413r += 4 * i + 6;1414}1415--curY;1416--x;1417}14181419// validDraw = true;1420uint16 *frameBuffer = ¤tScreen->frameBuffer[top * currentScreen->pitch];1421uint16 color16 = rgb32To16_B[(color >> 0) & 0xFF] | rgb32To16_G[(color >> 8) & 0xFF] | rgb32To16_R[(color >> 16) & 0xFF];14221423switch (inkEffect) {1424default: break;1425case INK_NONE:1426if (top <= bottom) {1427ScanEdge *edge = &scanEdgeBuffer[top];1428int32 sizeY = bottom - top;14291430for (int32 y = 0; y < sizeY; ++y) {1431if (edge->start < currentScreen->clipBound_X1)1432edge->start = currentScreen->clipBound_X1;1433if (edge->start > currentScreen->clipBound_X2)1434edge->start = currentScreen->clipBound_X2;14351436if (edge->end < currentScreen->clipBound_X1)1437edge->end = currentScreen->clipBound_X1;1438if (edge->end > currentScreen->clipBound_X2)1439edge->end = currentScreen->clipBound_X2;14401441int32 count = edge->end - edge->start;1442for (int32 x = 0; x < count; ++x) {1443frameBuffer[edge->start + x] = color16;1444}1445++edge;1446frameBuffer += currentScreen->pitch;1447}1448}1449break;14501451case INK_BLEND:1452if (top <= bottom) {1453ScanEdge *edge = &scanEdgeBuffer[top];1454int32 sizeY = bottom - top;14551456for (int32 y = 0; y < sizeY; ++y) {1457if (edge->start < currentScreen->clipBound_X1)1458edge->start = currentScreen->clipBound_X1;1459if (edge->start > currentScreen->clipBound_X2)1460edge->start = currentScreen->clipBound_X2;14611462if (edge->end < currentScreen->clipBound_X1)1463edge->end = currentScreen->clipBound_X1;1464if (edge->end > currentScreen->clipBound_X2)1465edge->end = currentScreen->clipBound_X2;14661467int32 count = edge->end - edge->start;1468for (int32 x = 0; x < count; ++x) {1469setPixelBlend(color16, frameBuffer[edge->start + x]);1470}14711472++edge;1473frameBuffer += currentScreen->pitch;1474}1475}1476break;14771478case INK_ALPHA:1479if (top <= bottom) {1480uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];1481uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];14821483ScanEdge *edge = &scanEdgeBuffer[top];1484int32 sizeY = bottom - top;14851486for (int32 y = 0; y < sizeY; ++y) {1487if (edge->start < currentScreen->clipBound_X1)1488edge->start = currentScreen->clipBound_X1;1489if (edge->start > currentScreen->clipBound_X2)1490edge->start = currentScreen->clipBound_X2;14911492if (edge->end < currentScreen->clipBound_X1)1493edge->end = currentScreen->clipBound_X1;1494if (edge->end > currentScreen->clipBound_X2)1495edge->end = currentScreen->clipBound_X2;14961497int32 count = edge->end - edge->start;1498for (int32 x = 0; x < count; ++x) {1499setPixelAlpha(color16, frameBuffer[edge->start + x], alpha);1500}1501++edge;1502frameBuffer += currentScreen->pitch;1503}1504}1505break;15061507case INK_ADD: {1508uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];1509if (top <= bottom) {1510ScanEdge *edge = &scanEdgeBuffer[top];1511int32 sizeY = bottom - top;15121513for (int32 y = 0; y < sizeY; ++y) {1514if (edge->start < currentScreen->clipBound_X1)1515edge->start = currentScreen->clipBound_X1;1516if (edge->start > currentScreen->clipBound_X2)1517edge->start = currentScreen->clipBound_X2;15181519if (edge->end < currentScreen->clipBound_X1)1520edge->end = currentScreen->clipBound_X1;1521if (edge->end > currentScreen->clipBound_X2)1522edge->end = currentScreen->clipBound_X2;15231524int32 count = edge->end - edge->start;1525for (int32 x = 0; x < count; ++x) {1526setPixelAdditive(color16, frameBuffer[edge->start + x]);1527}1528++edge;1529frameBuffer += currentScreen->pitch;1530}1531}1532break;1533}15341535case INK_SUB: {1536uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];1537if (top <= bottom) {1538ScanEdge *edge = &scanEdgeBuffer[top];1539int32 sizeY = bottom - top;15401541for (int32 y = 0; y < sizeY; ++y) {1542if (edge->start < currentScreen->clipBound_X1)1543edge->start = currentScreen->clipBound_X1;1544if (edge->start > currentScreen->clipBound_X2)1545edge->start = currentScreen->clipBound_X2;15461547if (edge->end < currentScreen->clipBound_X1)1548edge->end = currentScreen->clipBound_X1;1549if (edge->end > currentScreen->clipBound_X2)1550edge->end = currentScreen->clipBound_X2;15511552int32 count = edge->end - edge->start;1553for (int32 x = 0; x < count; ++x) {1554setPixelSubtractive(color16, frameBuffer[edge->start + x]);1555}1556++edge;1557frameBuffer += currentScreen->pitch;1558}1559}1560break;1561}15621563case INK_TINT:1564if (top <= bottom) {1565ScanEdge *edge = &scanEdgeBuffer[top];1566int32 sizeY = bottom - top;15671568for (int32 y = 0; y < sizeY; ++y) {1569if (edge->start < currentScreen->clipBound_X1)1570edge->start = currentScreen->clipBound_X1;1571if (edge->start > currentScreen->clipBound_X2)1572edge->start = currentScreen->clipBound_X2;15731574if (edge->end < currentScreen->clipBound_X1)1575edge->end = currentScreen->clipBound_X1;1576if (edge->end > currentScreen->clipBound_X2)1577edge->end = currentScreen->clipBound_X2;15781579int32 count = edge->end - edge->start;1580for (int32 x = 0; x < count; ++x) {1581frameBuffer[edge->start + x] = tintLookupTable[frameBuffer[edge->start + x]];1582}1583++edge;1584frameBuffer += currentScreen->pitch;1585}1586}1587break;15881589case INK_MASKED:1590if (top <= bottom) {1591ScanEdge *edge = &scanEdgeBuffer[top];1592int32 sizeY = bottom - top;15931594for (int32 y = 0; y < sizeY; ++y) {1595if (edge->start < currentScreen->clipBound_X1)1596edge->start = currentScreen->clipBound_X1;1597if (edge->start > currentScreen->clipBound_X2)1598edge->start = currentScreen->clipBound_X2;15991600if (edge->end < currentScreen->clipBound_X1)1601edge->end = currentScreen->clipBound_X1;1602if (edge->end > currentScreen->clipBound_X2)1603edge->end = currentScreen->clipBound_X2;16041605int32 count = edge->end - edge->start;1606for (int32 x = 0; x < count; ++x) {1607if (frameBuffer[edge->start + x] == maskColor)1608frameBuffer[edge->start + x] = color16;1609}1610++edge;1611frameBuffer += currentScreen->pitch;1612}1613}1614break;16151616case INK_UNMASKED:1617if (top <= bottom) {1618ScanEdge *edge = &scanEdgeBuffer[top];1619int32 sizeY = bottom - top;16201621for (int32 y = 0; y < sizeY; ++y) {1622if (edge->start < currentScreen->clipBound_X1)1623edge->start = currentScreen->clipBound_X1;1624if (edge->start > currentScreen->clipBound_X2)1625edge->start = currentScreen->clipBound_X2;16261627if (edge->end < currentScreen->clipBound_X1)1628edge->end = currentScreen->clipBound_X1;1629if (edge->end > currentScreen->clipBound_X2)1630edge->end = currentScreen->clipBound_X2;16311632int32 count = edge->end - edge->start;1633for (int32 x = 0; x < count; ++x) {1634if (frameBuffer[edge->start + x] != maskColor)1635frameBuffer[edge->start + x] = color16;1636}1637++edge;1638frameBuffer += currentScreen->pitch;1639}1640}1641break;1642}1643}1644}1645}1646void RSDK::DrawCircleOutline(int32 x, int32 y, int32 innerRadius, int32 outerRadius, uint32 color, int32 alpha, int32 inkEffect,1647bool32 screenRelative)1648{1649switch (inkEffect) {1650default: break;1651case INK_ALPHA:1652if (alpha > 0xFF)1653inkEffect = INK_NONE;1654else if (alpha <= 0)1655return;1656break;16571658case INK_ADD:1659case INK_SUB:1660if (alpha > 0xFF)1661alpha = 0xFF;1662else if (alpha <= 0)1663return;1664break;16651666case INK_TINT:1667if (!tintLookupTable)1668return;1669break;1670}16711672if (!screenRelative) {1673x = FROM_FIXED(x) - currentScreen->position.x;1674y = FROM_FIXED(y) - currentScreen->position.y;1675}16761677if (outerRadius > 0 && innerRadius < outerRadius) {1678int32 top = y - outerRadius;1679int32 left = x - outerRadius;1680int32 right = x + outerRadius;1681int32 bottom = y + outerRadius;16821683if (left < currentScreen->clipBound_X1)1684left = currentScreen->clipBound_X1;1685if (left > currentScreen->clipBound_X2)1686left = currentScreen->clipBound_X2;16871688if (right < currentScreen->clipBound_X1)1689right = currentScreen->clipBound_X1;1690if (right > currentScreen->clipBound_X2)1691right = currentScreen->clipBound_X2;16921693if (top < currentScreen->clipBound_Y1)1694top = currentScreen->clipBound_Y1;1695if (top > currentScreen->clipBound_Y1)1696top = currentScreen->clipBound_Y1;16971698if (bottom < currentScreen->clipBound_Y2)1699bottom = currentScreen->clipBound_Y2;1700if (bottom > currentScreen->clipBound_Y2)1701bottom = currentScreen->clipBound_Y2;17021703if (left != right && top != bottom) {1704int32 ir2 = innerRadius * innerRadius;1705int32 or2 = outerRadius * outerRadius;1706validDraw = true;1707uint16 *frameBuffer = ¤tScreen->frameBuffer[left + top * currentScreen->pitch];1708uint16 color16 = rgb32To16_B[(color >> 0) & 0xFF] | rgb32To16_G[(color >> 8) & 0xFF] | rgb32To16_R[(color >> 16) & 0xFF];1709int32 pitch = (left + currentScreen->pitch - right);17101711switch (inkEffect) {1712default: break;1713case INK_NONE:1714if (top < bottom) {1715int32 distY1 = top - y;1716int32 distY2 = bottom - top;1717do {1718int32 y2 = distY1 * distY1;1719if (left < right) {1720int32 distX1 = left - x;1721int32 distX2 = right - left;1722do {1723int32 r2 = y2 + distX1 * distX1;1724if (r2 >= ir2 && r2 < or2)1725*frameBuffer = color16;1726++frameBuffer;1727++distX1;1728--distX2;1729} while (distX2);1730}1731frameBuffer += pitch;1732--distY2;1733++distY1;1734} while (distY2);1735}1736break;17371738case INK_BLEND:1739if (top < bottom) {1740int32 distY1 = top - y;1741int32 distY2 = bottom - top;1742do {1743int32 y2 = distY1 * distY1;1744if (left < right) {1745int32 distX1 = left - x;1746int32 distX2 = right - left;1747do {1748int32 r2 = y2 + distX1 * distX1;1749if (r2 >= ir2 && r2 < or2)1750setPixelBlend(color16, *frameBuffer);1751++frameBuffer;1752++distX1;1753--distX2;1754} while (distX2);1755}1756frameBuffer += pitch;1757--distY2;1758++distY1;1759} while (distY2);1760}1761break;17621763case INK_ALPHA:1764if (top < bottom) {1765uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];1766uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];17671768int32 distY1 = top - y;1769int32 distY2 = bottom - top;1770do {1771int32 y2 = distY1 * distY1;1772if (left < right) {1773int32 distX1 = left - x;1774int32 distX2 = right - left;1775do {1776int32 r2 = y2 + distX1 * distX1;1777if (r2 >= ir2 && r2 < or2) {1778setPixelAlpha(color16, *frameBuffer, alpha);1779}1780++frameBuffer;1781++distX1;1782--distX2;1783} while (distX2);1784}1785frameBuffer += pitch;1786--distY2;1787++distY1;1788} while (distY2);1789}1790break;17911792case INK_ADD: {1793uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];1794if (top < bottom) {1795int32 distY1 = top - y;1796int32 distY2 = bottom - top;1797do {1798int32 y2 = distY1 * distY1;1799if (left < right) {1800int32 distX1 = left - x;1801int32 distX2 = right - left;1802do {1803int32 r2 = y2 + distX1 * distX1;1804if (r2 >= ir2 && r2 < or2) {1805setPixelAdditive(color16, *frameBuffer);1806}1807++frameBuffer;1808++distX1;1809--distX2;1810} while (distX2);1811}1812frameBuffer += pitch;1813--distY2;1814++distY1;1815} while (distY2);1816}1817break;1818}18191820case INK_SUB: {1821uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];1822if (top < bottom) {1823int32 distY1 = top - y;1824int32 distY2 = bottom - top;1825do {1826int32 y2 = distY1 * distY1;1827if (left < right) {1828int32 distX1 = left - x;1829int32 distX2 = right - left;1830do {1831int32 r2 = y2 + distX1 * distX1;1832if (r2 >= ir2 && r2 < or2) {1833setPixelSubtractive(color16, *frameBuffer);1834}1835++frameBuffer;1836++distX1;1837--distX2;1838} while (distX2);1839}1840frameBuffer += pitch;1841--distY2;1842++distY1;1843} while (distY2);1844}1845break;1846}18471848case INK_TINT:1849if (top < bottom) {1850int32 distY1 = top - y;1851int32 distY2 = bottom - top;1852do {1853int32 y2 = distY1 * distY1;1854if (left < right) {1855int32 distX1 = left - x;1856int32 distX2 = right - left;1857do {1858int32 r2 = y2 + distX1 * distX1;1859if (r2 >= ir2 && r2 < or2)1860*frameBuffer = tintLookupTable[*frameBuffer];1861++frameBuffer;1862++distX1;1863--distX2;1864} while (distX2);1865}1866frameBuffer += pitch;1867--distY2;1868++distY1;1869} while (distY2);1870}1871break;18721873case INK_MASKED:1874if (top < bottom) {1875int32 distY1 = top - y;1876int32 distY2 = bottom - top;1877do {1878int32 y2 = distY1 * distY1;1879if (left < right) {1880int32 distX1 = left - x;1881int32 distX2 = right - left;1882do {1883int32 r2 = y2 + distX1 * distX1;1884if (r2 >= ir2 && r2 < or2 && *frameBuffer == maskColor)1885*frameBuffer = color16;1886++frameBuffer;1887++distX1;1888--distX2;1889} while (distX2);1890}1891frameBuffer += pitch;1892--distY2;1893++distY1;1894} while (distY2);1895}1896break;18971898case INK_UNMASKED:1899if (top < bottom) {1900int32 distY1 = top - y;1901int32 distY2 = bottom - top;1902do {1903int32 y2 = distY1 * distY1;1904if (left < right) {1905int32 distX1 = left - x;1906int32 distX2 = right - left;1907do {1908int32 r2 = y2 + distX1 * distX1;1909if (r2 >= ir2 && r2 < or2 && *frameBuffer != maskColor)1910*frameBuffer = color16;1911++frameBuffer;1912++distX1;1913--distX2;1914} while (distX2);1915}1916frameBuffer += pitch;1917--distY2;1918++distY1;1919} while (distY2);1920}1921break;1922}1923}1924}1925}19261927void RSDK::DrawFace(Vector2 *vertices, int32 vertCount, int32 r, int32 g, int32 b, int32 alpha, int32 inkEffect)1928{1929switch (inkEffect) {1930default: break;1931case INK_ALPHA:1932if (alpha > 0xFF)1933inkEffect = INK_NONE;1934else if (alpha <= 0)1935return;1936break;19371938case INK_ADD:1939case INK_SUB:1940if (alpha > 0xFF)1941alpha = 0xFF;1942else if (alpha <= 0)1943return;1944break;19451946case INK_TINT:1947if (!tintLookupTable)1948return;1949break;1950}19511952int32 top = 0x7FFFFFFF;1953int32 bottom = -0x10000;1954for (int32 v = 0; v < vertCount; ++v) {1955if (vertices[v].y < top)1956top = vertices[v].y;1957if (vertices[v].y > bottom)1958bottom = vertices[v].y;1959}19601961int32 topScreen = FROM_FIXED(top);1962int32 bottomScreen = FROM_FIXED(bottom);19631964if (topScreen < currentScreen->clipBound_Y1)1965topScreen = currentScreen->clipBound_Y1;1966if (topScreen > currentScreen->clipBound_Y2)1967topScreen = currentScreen->clipBound_Y2;19681969if (bottomScreen < currentScreen->clipBound_Y1)1970bottomScreen = currentScreen->clipBound_Y1;1971if (bottomScreen > currentScreen->clipBound_Y2)1972bottomScreen = currentScreen->clipBound_Y2;19731974if (topScreen != bottomScreen) {1975ScanEdge *edge = &scanEdgeBuffer[topScreen];1976for (int32 s = topScreen; s <= bottomScreen; ++s) {1977edge->start = 0x7FFF;1978edge->end = -1;1979++edge;1980}19811982for (int32 v = 0; v < vertCount - 1; ++v) {1983ProcessScanEdge(vertices[v + 0].x, vertices[v + 0].y, vertices[v + 1].x, vertices[v + 1].y);1984}1985ProcessScanEdge(vertices[0].x, vertices[0].y, vertices[vertCount - 1].x, vertices[vertCount - 1].y);19861987uint16 *frameBuffer = ¤tScreen->frameBuffer[topScreen * currentScreen->pitch];1988uint16 color16 = rgb32To16_B[b] | rgb32To16_G[g] | rgb32To16_R[r];19891990edge = &scanEdgeBuffer[topScreen];1991switch (inkEffect) {1992default: break;19931994case INK_NONE:1995for (int32 s = topScreen; s <= bottomScreen; ++s) {1996if (edge->start < currentScreen->clipBound_X1)1997edge->start = currentScreen->clipBound_X1;1998if (edge->start > currentScreen->clipBound_X2)1999edge->start = currentScreen->clipBound_X2;20002001if (edge->end < currentScreen->clipBound_X1)2002edge->end = currentScreen->clipBound_X1;2003if (edge->end > currentScreen->clipBound_X2)2004edge->end = currentScreen->clipBound_X2;20052006int32 count = edge->end - edge->start;2007for (int32 x = 0; x < count; ++x) {2008frameBuffer[edge->start + x] = color16;2009}2010++edge;2011frameBuffer += currentScreen->pitch;2012}2013break;20142015case INK_BLEND:2016for (int32 s = topScreen; s <= bottomScreen; ++s) {2017if (edge->start < currentScreen->clipBound_X1)2018edge->start = currentScreen->clipBound_X1;2019if (edge->start > currentScreen->clipBound_X2)2020edge->start = currentScreen->clipBound_X2;20212022if (edge->end < currentScreen->clipBound_X1)2023edge->end = currentScreen->clipBound_X1;2024if (edge->end > currentScreen->clipBound_X2)2025edge->end = currentScreen->clipBound_X2;20262027int32 count = edge->end - edge->start;2028for (int32 x = 0; x < count; ++x) {2029setPixelBlend(color16, frameBuffer[edge->start + x]);2030}2031++edge;2032frameBuffer += currentScreen->pitch;2033}2034break;20352036case INK_ALPHA: {2037uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];2038uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];20392040for (int32 s = topScreen; s <= bottomScreen; ++s) {2041if (edge->start < currentScreen->clipBound_X1)2042edge->start = currentScreen->clipBound_X1;2043if (edge->start > currentScreen->clipBound_X2)2044edge->start = currentScreen->clipBound_X2;20452046if (edge->end < currentScreen->clipBound_X1)2047edge->end = currentScreen->clipBound_X1;2048if (edge->end > currentScreen->clipBound_X2)2049edge->end = currentScreen->clipBound_X2;20502051int32 count = edge->end - edge->start;2052for (int32 x = 0; x < count; ++x) {2053setPixelAlpha(color16, frameBuffer[edge->start + x], alpha);2054}2055++edge;2056frameBuffer += currentScreen->pitch;2057}2058break;2059}20602061case INK_ADD: {2062uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];20632064for (int32 s = topScreen; s <= bottomScreen; ++s) {2065if (edge->start < currentScreen->clipBound_X1)2066edge->start = currentScreen->clipBound_X1;2067if (edge->start > currentScreen->clipBound_X2)2068edge->start = currentScreen->clipBound_X2;20692070if (edge->end < currentScreen->clipBound_X1)2071edge->end = currentScreen->clipBound_X1;2072if (edge->end > currentScreen->clipBound_X2)2073edge->end = currentScreen->clipBound_X2;20742075int32 count = edge->end - edge->start;2076for (int32 x = 0; x < count; ++x) {2077setPixelAdditive(color16, frameBuffer[edge->start + x]);2078}20792080++edge;2081frameBuffer += currentScreen->pitch;2082}2083break;2084}20852086case INK_SUB: {2087uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];2088for (int32 s = topScreen; s <= bottomScreen; ++s) {2089if (edge->start < currentScreen->clipBound_X1)2090edge->start = currentScreen->clipBound_X1;2091if (edge->start > currentScreen->clipBound_X2)2092edge->start = currentScreen->clipBound_X2;20932094if (edge->end < currentScreen->clipBound_X1)2095edge->end = currentScreen->clipBound_X1;2096if (edge->end > currentScreen->clipBound_X2)2097edge->end = currentScreen->clipBound_X2;20982099int32 count = edge->end - edge->start;2100for (int32 x = 0; x < count; ++x) {2101setPixelSubtractive(color16, frameBuffer[edge->start + x]);2102}21032104++edge;2105frameBuffer += currentScreen->pitch;2106}2107break;2108}21092110case INK_TINT:2111for (int32 s = topScreen; s <= bottomScreen; ++s) {2112if (edge->start < currentScreen->clipBound_X1)2113edge->start = currentScreen->clipBound_X1;2114if (edge->start > currentScreen->clipBound_X2)2115edge->start = currentScreen->clipBound_X2;21162117if (edge->end < currentScreen->clipBound_X1)2118edge->end = currentScreen->clipBound_X1;2119if (edge->end > currentScreen->clipBound_X2)2120edge->end = currentScreen->clipBound_X2;21212122int32 count = edge->end - edge->start;2123for (int32 x = 0; x < count; ++x) {2124frameBuffer[edge->start + x] = tintLookupTable[frameBuffer[edge->start + x]];2125}21262127++edge;2128frameBuffer += currentScreen->pitch;2129}2130break;21312132case INK_MASKED:2133for (int32 s = topScreen; s <= bottomScreen; ++s) {2134if (edge->start < currentScreen->clipBound_X1)2135edge->start = currentScreen->clipBound_X1;2136if (edge->start > currentScreen->clipBound_X2)2137edge->start = currentScreen->clipBound_X2;21382139if (edge->end < currentScreen->clipBound_X1)2140edge->end = currentScreen->clipBound_X1;2141if (edge->end > currentScreen->clipBound_X2)2142edge->end = currentScreen->clipBound_X2;21432144int32 count = edge->end - edge->start;2145for (int32 x = 0; x < count; ++x) {2146if (frameBuffer[edge->start + x] == maskColor)2147frameBuffer[edge->start + x] = color16;2148}21492150++edge;2151frameBuffer += currentScreen->pitch;2152}2153break;21542155case INK_UNMASKED:2156for (int32 s = topScreen; s <= bottomScreen; ++s) {2157if (edge->start < currentScreen->clipBound_X1)2158edge->start = currentScreen->clipBound_X1;2159if (edge->start > currentScreen->clipBound_X2)2160edge->start = currentScreen->clipBound_X2;21612162if (edge->end < currentScreen->clipBound_X1)2163edge->end = currentScreen->clipBound_X1;2164if (edge->end > currentScreen->clipBound_X2)2165edge->end = currentScreen->clipBound_X2;21662167int32 count = edge->end - edge->start;2168for (int32 x = 0; x < count; ++x) {2169if (frameBuffer[edge->start + x] != maskColor)2170frameBuffer[edge->start + x] = color16;2171}21722173++edge;2174frameBuffer += currentScreen->pitch;2175}2176break;2177}2178}2179}2180void RSDK::DrawBlendedFace(Vector2 *vertices, uint32 *colors, int32 vertCount, int32 alpha, int32 inkEffect)2181{2182switch (inkEffect) {2183default: break;2184case INK_ALPHA:2185if (alpha > 0xFF)2186inkEffect = INK_NONE;2187else if (alpha <= 0)2188return;2189break;21902191case INK_ADD:2192case INK_SUB:2193if (alpha > 0xFF)2194alpha = 0xFF;2195else if (alpha <= 0)2196return;2197break;21982199case INK_TINT:2200if (!tintLookupTable)2201return;2202break;2203}22042205int32 top = 0x7FFFFFFF;2206int32 bottom = -0x10000;2207for (int32 v = 0; v < vertCount; ++v) {2208if (vertices[v].y < top)2209top = vertices[v].y;2210if (vertices[v].y > bottom)2211bottom = vertices[v].y;2212}22132214int32 topScreen = FROM_FIXED(top);2215int32 bottomScreen = FROM_FIXED(bottom);22162217if (topScreen < currentScreen->clipBound_Y1)2218topScreen = currentScreen->clipBound_Y1;2219if (topScreen > currentScreen->clipBound_Y2)2220topScreen = currentScreen->clipBound_Y2;22212222if (bottomScreen < currentScreen->clipBound_Y1)2223bottomScreen = currentScreen->clipBound_Y1;2224if (bottomScreen > currentScreen->clipBound_Y2)2225bottomScreen = currentScreen->clipBound_Y2;22262227if (topScreen != bottomScreen) {2228ScanEdge *edge = &scanEdgeBuffer[topScreen];2229for (int32 s = topScreen; s <= bottomScreen; ++s) {2230edge->start = 0x7FFF;2231edge->end = -1;2232++edge;2233}22342235for (int32 v = 0; v < vertCount - 1; ++v) {2236ProcessScanEdgeClr(colors[v + 0], colors[v + 1], vertices[v + 0].x, vertices[v + 0].y, vertices[v + 1].x, vertices[v + 1].y);2237}2238ProcessScanEdgeClr(colors[vertCount - 1], colors[0], vertices[vertCount - 1].x, vertices[vertCount - 1].y, vertices[0].x, vertices[0].y);22392240uint16 *frameBuffer = ¤tScreen->frameBuffer[topScreen * currentScreen->pitch];22412242edge = &scanEdgeBuffer[topScreen];2243switch (inkEffect) {2244default: break;2245case INK_NONE:2246for (int32 s = topScreen; s <= bottomScreen; ++s) {2247int32 count = edge->end - edge->start;2248int32 deltaR = 0;2249int32 deltaG = 0;2250int32 deltaB = 0;2251if (count > 0) {2252deltaR = (edge->endR - edge->startR) / count;2253deltaG = (edge->endG - edge->startG) / count;2254deltaB = (edge->endB - edge->startB) / count;2255}2256int32 startR = edge->startR;2257int32 startG = edge->startG;2258int32 startB = edge->startB;22592260if (edge->start > currentScreen->clipBound_X2) {2261edge->start = currentScreen->clipBound_X2;2262}2263else if (edge->start < currentScreen->clipBound_X1) {2264int32 dist = (currentScreen->clipBound_X1 - edge->start);2265startR += deltaR * dist;2266startG += deltaG * dist;2267startB += deltaB * dist;2268count -= dist;2269edge->start = currentScreen->clipBound_X1;2270}22712272if (edge->end < currentScreen->clipBound_X1) {2273edge->end = currentScreen->clipBound_X1;2274count = currentScreen->clipBound_X1 - edge->start;2275}22762277if (edge->end > currentScreen->clipBound_X2) {2278edge->end = currentScreen->clipBound_X2;2279count = currentScreen->clipBound_X2 - edge->start;2280}22812282for (int32 x = 0; x < count; ++x) {2283frameBuffer[edge->start + x] = (startB >> 19) + ((startG >> 13) & 0x7E0) + ((startR >> 8) & 0xF800);22842285startR += deltaR;2286startG += deltaG;2287startB += deltaB;2288}2289++edge;2290frameBuffer += currentScreen->pitch;2291}2292break;22932294case INK_BLEND:2295for (int32 s = topScreen; s <= bottomScreen; ++s) {2296int32 start = edge->start;2297int32 count = edge->end - edge->start;2298int32 deltaR = 0;2299int32 deltaG = 0;2300int32 deltaB = 0;2301if (count > 0) {2302deltaR = (edge->endR - edge->startR) / count;2303deltaG = (edge->endG - edge->startG) / count;2304deltaB = (edge->endB - edge->startB) / count;2305}2306int32 startR = edge->startR;2307int32 startG = edge->startG;2308int32 startB = edge->startB;23092310if (start > currentScreen->clipBound_X2) {2311edge->start = currentScreen->clipBound_X2;2312}23132314if (start < currentScreen->clipBound_X1) {2315startR += deltaR * (currentScreen->clipBound_X1 - edge->start);2316startG += deltaG * (currentScreen->clipBound_X1 - edge->start);2317startB += deltaB * (currentScreen->clipBound_X1 - edge->start);2318count -= (currentScreen->clipBound_X1 - edge->start);2319edge->start = currentScreen->clipBound_X1;2320}23212322if (edge->end < currentScreen->clipBound_X1) {2323edge->end = currentScreen->clipBound_X1;2324}23252326if (edge->end > currentScreen->clipBound_X2) {2327edge->end = currentScreen->clipBound_X2;2328count = currentScreen->clipBound_X2 - edge->start;2329}23302331for (int32 x = 0; x < count; ++x) {2332uint16 color = (startB >> 19) + ((startG >> 13) & 0x7E0) + ((startR >> 8) & 0xF800);2333setPixelBlend(color, frameBuffer[edge->start + x]);23342335startR += deltaR;2336startG += deltaG;2337startB += deltaB;2338}23392340++edge;2341frameBuffer += currentScreen->pitch;2342}2343break;23442345case INK_ALPHA: {2346uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];2347uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];23482349for (int32 s = topScreen; s <= bottomScreen; ++s) {2350int32 start = edge->start;2351int32 count = edge->end - edge->start;2352int32 deltaR = 0;2353int32 deltaG = 0;2354int32 deltaB = 0;2355if (count > 0) {2356deltaR = (edge->endR - edge->startR) / count;2357deltaG = (edge->endG - edge->startG) / count;2358deltaB = (edge->endB - edge->startB) / count;2359}2360int32 startR = edge->startR;2361int32 startG = edge->startG;2362int32 startB = edge->startB;23632364if (start > currentScreen->clipBound_X2) {2365edge->start = currentScreen->clipBound_X2;2366}23672368if (start < currentScreen->clipBound_X1) {2369startR += deltaR * (currentScreen->clipBound_X1 - edge->start);2370startG += deltaG * (currentScreen->clipBound_X1 - edge->start);2371startB += deltaB * (currentScreen->clipBound_X1 - edge->start);2372count -= (currentScreen->clipBound_X1 - edge->start);2373edge->start = currentScreen->clipBound_X1;2374}23752376if (edge->end < currentScreen->clipBound_X1) {2377edge->end = currentScreen->clipBound_X1;2378}23792380if (edge->end > currentScreen->clipBound_X2) {2381edge->end = currentScreen->clipBound_X2;2382count = currentScreen->clipBound_X2 - edge->start;2383}23842385for (int32 x = 0; x < count; ++x) {2386uint16 color = (startB >> 19) + ((startG >> 13) & 0x7E0) + ((startR >> 8) & 0xF800);2387setPixelAlpha(color, frameBuffer[edge->start + x], alpha);23882389startR += deltaR;2390startG += deltaG;2391startB += deltaB;2392}2393++edge;2394frameBuffer += currentScreen->pitch;2395}2396break;2397}23982399case INK_ADD: {2400uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];24012402for (int32 s = topScreen; s <= bottomScreen; ++s) {2403int32 start = edge->start;2404int32 count = edge->end - edge->start;2405int32 deltaR = 0;2406int32 deltaG = 0;2407int32 deltaB = 0;2408if (count > 0) {2409deltaR = (edge->endR - edge->startR) / count;2410deltaG = (edge->endG - edge->startG) / count;2411deltaB = (edge->endB - edge->startB) / count;2412}2413int32 startR = edge->startR;2414int32 startG = edge->startG;2415int32 startB = edge->startB;24162417if (start > currentScreen->clipBound_X2) {2418edge->start = currentScreen->clipBound_X2;2419}24202421if (start < currentScreen->clipBound_X1) {2422startR += deltaR * (currentScreen->clipBound_X1 - edge->start);2423startG += deltaG * (currentScreen->clipBound_X1 - edge->start);2424startB += deltaB * (currentScreen->clipBound_X1 - edge->start);2425count -= (currentScreen->clipBound_X1 - edge->start);2426edge->start = currentScreen->clipBound_X1;2427}24282429if (edge->end < currentScreen->clipBound_X1) {2430edge->end = currentScreen->clipBound_X1;2431}24322433if (edge->end > currentScreen->clipBound_X2) {2434edge->end = currentScreen->clipBound_X2;2435count = currentScreen->clipBound_X2 - edge->start;2436}24372438for (int32 x = 0; x < count; ++x) {2439uint16 color = (startB >> 19) + ((startG >> 13) & 0x7E0) + ((startR >> 8) & 0xF800);2440setPixelAdditive(color, frameBuffer[edge->start + x]);24412442startR += deltaR;2443startG += deltaG;2444startB += deltaB;2445}24462447++edge;2448frameBuffer += currentScreen->pitch;2449}2450break;2451}24522453case INK_SUB: {2454uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];24552456for (int32 s = topScreen; s <= bottomScreen; ++s) {2457int32 start = edge->start;2458int32 count = edge->end - edge->start;2459int32 deltaR = 0;2460int32 deltaG = 0;2461int32 deltaB = 0;2462if (count > 0) {2463deltaR = (edge->endR - edge->startR) / count;2464deltaG = (edge->endG - edge->startG) / count;2465deltaB = (edge->endB - edge->startB) / count;2466}2467int32 startR = edge->startR;2468int32 startG = edge->startG;2469int32 startB = edge->startB;24702471if (start > currentScreen->clipBound_X2) {2472edge->start = currentScreen->clipBound_X2;2473}24742475if (start < currentScreen->clipBound_X1) {2476startR += deltaR * (currentScreen->clipBound_X1 - edge->start);2477startG += deltaG * (currentScreen->clipBound_X1 - edge->start);2478startB += deltaB * (currentScreen->clipBound_X1 - edge->start);2479count -= (currentScreen->clipBound_X1 - edge->start);2480edge->start = currentScreen->clipBound_X1;2481}24822483if (edge->end < currentScreen->clipBound_X1) {2484edge->end = currentScreen->clipBound_X1;2485}24862487if (edge->end > currentScreen->clipBound_X2) {2488edge->end = currentScreen->clipBound_X2;2489count = currentScreen->clipBound_X2 - edge->start;2490}24912492for (int32 x = 0; x < count; ++x) {2493uint16 color = (startB >> 19) + ((startG >> 13) & 0x7E0) + ((startR >> 8) & 0xF800);2494setPixelSubtractive(color, frameBuffer[edge->start + x]);24952496startR += deltaR;2497startG += deltaG;2498startB += deltaB;2499}25002501++edge;2502frameBuffer += currentScreen->pitch;2503}2504break;2505}25062507case INK_TINT:2508for (int32 s = topScreen; s <= bottomScreen; ++s) {2509int32 start = edge->start;2510int32 count = edge->end - edge->start;25112512#if RETRO_USE_ORIGINAL_CODE2513// Unused, ifdef'd out to help out ports for weaker hardware2514int32 deltaR = 0;2515int32 deltaG = 0;2516int32 deltaB = 0;2517if (count > 0) {2518deltaR = (edge->endR - edge->startR) / count;2519deltaG = (edge->endG - edge->startG) / count;2520deltaB = (edge->endB - edge->startB) / count;2521}2522int32 startR = edge->startR;2523int32 startG = edge->startG;2524int32 startB = edge->startB;2525#endif25262527if (start > currentScreen->clipBound_X2) {2528edge->start = currentScreen->clipBound_X2;2529}25302531if (start < currentScreen->clipBound_X1) {2532#if RETRO_USE_ORIGINAL_CODE2533// Unused, ifdef'd out to help out ports for weaker hardware2534startR += deltaR * (currentScreen->clipBound_X1 - edge->start);2535startG += deltaG * (currentScreen->clipBound_X1 - edge->start);2536startB += deltaB * (currentScreen->clipBound_X1 - edge->start);2537#endif25382539count -= (currentScreen->clipBound_X1 - edge->start);2540edge->start = currentScreen->clipBound_X1;2541}25422543if (edge->end < currentScreen->clipBound_X1) {2544edge->end = currentScreen->clipBound_X1;2545}25462547if (edge->end > currentScreen->clipBound_X2) {2548edge->end = currentScreen->clipBound_X2;2549count = currentScreen->clipBound_X2 - edge->start;2550}25512552for (int32 x = 0; x < count; ++x) {2553frameBuffer[edge->start + x] = tintLookupTable[frameBuffer[edge->start + x]];25542555#if RETRO_USE_ORIGINAL_CODE2556// Unused, ifdef'd out to help out ports for weaker hardware2557startR += deltaR;2558startG += deltaG;2559startB += deltaB;2560#endif2561}25622563++edge;2564frameBuffer += currentScreen->pitch;2565}2566break;25672568case INK_MASKED:2569for (int32 s = topScreen; s <= bottomScreen; ++s) {2570int32 start = edge->start;2571int32 count = edge->end - edge->start;2572int32 deltaR = 0;2573int32 deltaG = 0;2574int32 deltaB = 0;2575if (count > 0) {2576deltaR = (edge->endR - edge->startR) / count;2577deltaG = (edge->endG - edge->startG) / count;2578deltaB = (edge->endB - edge->startB) / count;2579}2580int32 startR = edge->startR;2581int32 startG = edge->startG;2582int32 startB = edge->startB;25832584if (start > currentScreen->clipBound_X2) {2585edge->start = currentScreen->clipBound_X2;2586}25872588if (start < currentScreen->clipBound_X1) {2589startR += deltaR * (currentScreen->clipBound_X1 - edge->start);2590startG += deltaG * (currentScreen->clipBound_X1 - edge->start);2591startB += deltaB * (currentScreen->clipBound_X1 - edge->start);2592count -= (currentScreen->clipBound_X1 - edge->start);2593edge->start = currentScreen->clipBound_X1;2594}25952596if (edge->end < currentScreen->clipBound_X1 || edge->end > currentScreen->clipBound_X2) {2597edge->end = currentScreen->clipBound_X2;2598count = currentScreen->clipBound_X2 - edge->start;2599}26002601for (int32 x = 0; x < count; ++x) {2602if (frameBuffer[edge->start + x] == maskColor)2603frameBuffer[edge->start + x] = (startB >> 19) + ((startG >> 13) & 0x7E0) + ((startR >> 8) & 0xF800);26042605startR += deltaR;2606startG += deltaG;2607startB += deltaB;2608}26092610++edge;2611frameBuffer += currentScreen->pitch;2612}2613break;26142615case INK_UNMASKED:2616for (int32 s = topScreen; s <= bottomScreen; ++s) {2617int32 start = edge->start;2618int32 count = edge->end - edge->start;2619int32 deltaR = 0;2620int32 deltaG = 0;2621int32 deltaB = 0;2622if (count > 0) {2623deltaR = (edge->endR - edge->startR) / count;2624deltaG = (edge->endG - edge->startG) / count;2625deltaB = (edge->endB - edge->startB) / count;2626}2627int32 startR = edge->startR;2628int32 startG = edge->startG;2629int32 startB = edge->startB;26302631if (start > currentScreen->clipBound_X2) {2632edge->start = currentScreen->clipBound_X2;2633}26342635if (start < currentScreen->clipBound_X1) {2636startR += deltaR * (currentScreen->clipBound_X1 - edge->start);2637startG += deltaG * (currentScreen->clipBound_X1 - edge->start);2638startB += deltaB * (currentScreen->clipBound_X1 - edge->start);2639count -= (currentScreen->clipBound_X1 - edge->start);2640edge->start = currentScreen->clipBound_X1;2641}26422643if (edge->end < currentScreen->clipBound_X1) {2644edge->end = currentScreen->clipBound_X1;2645}26462647if (edge->end > currentScreen->clipBound_X2) {2648edge->end = currentScreen->clipBound_X2;2649count = currentScreen->clipBound_X2 - edge->start;2650}26512652for (int32 x = 0; x < count; ++x) {2653if (frameBuffer[edge->start + x] != maskColor)2654frameBuffer[edge->start + x] = (startB >> 19) + ((startG >> 13) & 0x7E0) + ((startR >> 8) & 0xF800);26552656startR += deltaR;2657startG += deltaG;2658startB += deltaB;2659}26602661++edge;2662frameBuffer += currentScreen->pitch;2663}2664break;2665}2666}2667}26682669void RSDK::DrawSprite(Animator *animator, Vector2 *position, bool32 screenRelative)2670{2671if (animator && animator->frames) {2672SpriteFrame *frame = &animator->frames[animator->frameID];2673Vector2 pos;2674if (!position)2675pos = sceneInfo.entity->position;2676else2677pos = *position;26782679pos.x >>= 0x10;2680pos.y >>= 0x10;2681if (!screenRelative) {2682pos.x -= currentScreen->position.x;2683pos.y -= currentScreen->position.y;2684}26852686int32 rotation = sceneInfo.entity->rotation;2687int32 drawFX = sceneInfo.entity->drawFX;2688if (sceneInfo.entity->drawFX & FX_ROTATE) {2689switch (animator->rotationStyle) {2690case ROTSTYLE_NONE:2691rotation = 0;2692if ((sceneInfo.entity->drawFX & FX_ROTATE) != FX_NONE)2693drawFX ^= FX_ROTATE;2694break;26952696case ROTSTYLE_FULL:2697rotation = sceneInfo.entity->rotation & 0x1FF;2698if (rotation == 0)2699drawFX ^= FX_ROTATE;2700break;27012702case ROTSTYLE_45DEG: // 0x00, 0x40, 0x80, 0xC0, 0x100, 0x140, 0x180, 0x1C02703rotation = (sceneInfo.entity->rotation + 0x20) & 0x1C0;2704if (rotation == 0)2705drawFX ^= FX_ROTATE;2706break;27072708case ROTSTYLE_90DEG: // 0x00, 0x80, 0x100, 0x1802709rotation = (sceneInfo.entity->rotation + 0x40) & 0x180;2710if (rotation == 0)2711drawFX ^= FX_ROTATE;2712break;27132714case ROTSTYLE_180DEG: // 0x00, 0x1002715rotation = (sceneInfo.entity->rotation + 0x80) & 0x100;2716if (rotation == 0)2717drawFX ^= FX_ROTATE;2718break;27192720case ROTSTYLE_STATICFRAMES:2721if (sceneInfo.entity->rotation >= 0x100)2722rotation = 0x08 - ((0x214 - sceneInfo.entity->rotation) >> 6);2723else2724rotation = (sceneInfo.entity->rotation + 20) >> 6;27252726switch (rotation) {2727case 0: // 0 deg2728case 8: // 360 deg2729rotation = 0x00;2730if ((sceneInfo.entity->drawFX & FX_SCALE) != FX_NONE)2731drawFX ^= FX_ROTATE;2732break;27332734case 1: // 45 deg2735rotation = 0x80;2736frame += animator->frameCount;2737if (sceneInfo.entity->direction)2738rotation = 0x00;2739break;27402741case 2: // 90 deg2742rotation = 0x80;2743break;27442745case 3: // 135 deg2746rotation = 0x100;2747frame += animator->frameCount;2748if (sceneInfo.entity->direction)2749rotation = 0x80;2750break;27512752case 4: // 180 deg2753rotation = 0x100;2754break;27552756case 5: // 225 deg2757rotation = 0x180;2758frame += animator->frameCount;2759if (sceneInfo.entity->direction)2760rotation = 0x100;2761break;27622763case 6: // 270 deg2764rotation = 0x180;2765break;27662767case 7: // 315 deg2768rotation = 0x180;2769frame += animator->frameCount;2770if (!sceneInfo.entity->direction)2771rotation = 0;2772break;27732774default: break;2775}2776break;27772778default: break;2779}2780}27812782switch (drawFX) {2783case FX_NONE:2784DrawSpriteFlipped(pos.x + frame->pivotX, pos.y + frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY, FLIP_NONE,2785sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, frame->sheetID);2786break;27872788case FX_FLIP:2789switch (sceneInfo.entity->direction) {2790case FLIP_NONE:2791DrawSpriteFlipped(pos.x + frame->pivotX, pos.y + frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY,2792FLIP_NONE, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, frame->sheetID);2793break;27942795case FLIP_X:2796DrawSpriteFlipped(pos.x - frame->width - frame->pivotX, pos.y + frame->pivotY, frame->width, frame->height, frame->sprX,2797frame->sprY, FLIP_X, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, frame->sheetID);2798break;27992800case FLIP_Y:2801DrawSpriteFlipped(pos.x + frame->pivotX, pos.y - frame->height - frame->pivotY, frame->width, frame->height, frame->sprX,2802frame->sprY, FLIP_Y, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, frame->sheetID);2803break;28042805case FLIP_XY:2806DrawSpriteFlipped(pos.x - frame->width - frame->pivotX, pos.y - frame->height - frame->pivotY, frame->width, frame->height,2807frame->sprX, frame->sprY, FLIP_XY, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, frame->sheetID);2808break;28092810default: break;2811}2812break;28132814case FX_ROTATE:2815DrawSpriteRotozoom(pos.x, pos.y, frame->pivotX, frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY, 0x200, 0x200,2816FLIP_NONE, rotation, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, frame->sheetID);2817break;28182819case FX_ROTATE | FX_FLIP:2820DrawSpriteRotozoom(pos.x, pos.y, frame->pivotX, frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY, 0x200, 0x200,2821sceneInfo.entity->direction & FLIP_X, rotation, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha,2822frame->sheetID);2823break;28242825case FX_SCALE:2826DrawSpriteRotozoom(pos.x, pos.y, frame->pivotX, frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY,2827sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_NONE, 0, sceneInfo.entity->inkEffect,2828sceneInfo.entity->alpha, frame->sheetID);2829break;28302831case FX_SCALE | FX_FLIP:2832DrawSpriteRotozoom(pos.x, pos.y, frame->pivotX, frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY,2833sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, sceneInfo.entity->direction & FLIP_X, 0,2834sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, frame->sheetID);2835break;28362837case FX_SCALE | FX_ROTATE:2838DrawSpriteRotozoom(pos.x, pos.y, frame->pivotX, frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY,2839sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_NONE, rotation, sceneInfo.entity->inkEffect,2840sceneInfo.entity->alpha, frame->sheetID);2841break;28422843case FX_SCALE | FX_ROTATE | FX_FLIP:2844DrawSpriteRotozoom(pos.x, pos.y, frame->pivotX, frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY,2845sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, sceneInfo.entity->direction & FLIP_X, rotation,2846sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, frame->sheetID);2847break;28482849default: break;2850}2851}2852}2853void RSDK::DrawSpriteFlipped(int32 x, int32 y, int32 width, int32 height, int32 sprX, int32 sprY, int32 direction, int32 inkEffect, int32 alpha,2854int32 sheetID)2855{2856switch (inkEffect) {2857default: break;2858case INK_ALPHA:2859if (alpha > 0xFF)2860inkEffect = INK_NONE;2861else if (alpha <= 0)2862return;2863break;28642865case INK_ADD:2866case INK_SUB:2867if (alpha > 0xFF)2868alpha = 0xFF;2869else if (alpha <= 0)2870return;2871break;28722873case INK_TINT:2874if (!tintLookupTable)2875return;2876break;2877}2878int32 widthFlip = width;2879int32 heightFlip = height;28802881if (width + x > currentScreen->clipBound_X2)2882width = currentScreen->clipBound_X2 - x;28832884if (x < currentScreen->clipBound_X1) {2885int32 val = x - currentScreen->clipBound_X1;2886sprX -= val;2887width += val;2888widthFlip += 2 * val;2889x = currentScreen->clipBound_X1;2890}28912892if (height + y > currentScreen->clipBound_Y2)2893height = currentScreen->clipBound_Y2 - y;28942895if (y < currentScreen->clipBound_Y1) {2896int32 val = y - currentScreen->clipBound_Y1;2897sprY -= val;2898height += val;2899heightFlip += 2 * val;2900y = currentScreen->clipBound_Y1;2901}29022903if (width <= 0 || height <= 0)2904return;29052906GFXSurface *surface = &gfxSurface[sheetID];2907validDraw = true;2908int32 pitch = currentScreen->pitch - width;2909int32 gfxPitch = 0;2910uint8 *lineBuffer = NULL;2911uint8 *pixels = NULL;2912uint16 *frameBuffer = NULL;29132914switch (direction) {2915default: break;29162917case FLIP_NONE:2918gfxPitch = surface->width - width;2919lineBuffer = &gfxLineBuffer[y];2920pixels = &surface->pixels[sprX + surface->width * sprY];2921frameBuffer = ¤tScreen->frameBuffer[x + currentScreen->pitch * y];2922switch (inkEffect) {2923case INK_NONE:2924while (height--) {2925uint16 *activePalette = fullPalette[*lineBuffer];2926lineBuffer++;2927int32 w = width;2928while (w--) {2929if (*pixels > 0)2930*frameBuffer = activePalette[*pixels];2931++pixels;2932++frameBuffer;2933}2934frameBuffer += pitch;2935pixels += gfxPitch;2936}2937break;29382939case INK_BLEND:2940while (height--) {2941uint16 *activePalette = fullPalette[*lineBuffer];2942lineBuffer++;2943int32 w = width;2944while (w--) {2945if (*pixels > 0)2946setPixelBlend(activePalette[*pixels], *frameBuffer);2947++pixels;2948++frameBuffer;2949}2950frameBuffer += pitch;2951pixels += gfxPitch;2952}2953break;29542955case INK_ALPHA: {2956uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];2957uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];29582959while (height--) {2960uint16 *activePalette = fullPalette[*lineBuffer];2961lineBuffer++;2962int32 w = width;2963while (w--) {2964if (*pixels > 0) {2965uint16 color = activePalette[*pixels];2966setPixelAlpha(color, *frameBuffer, alpha);2967}2968++pixels;2969++frameBuffer;2970}2971frameBuffer += pitch;2972pixels += gfxPitch;2973}2974break;2975}29762977case INK_ADD: {2978uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];2979while (height--) {2980uint16 *activePalette = fullPalette[*lineBuffer];2981lineBuffer++;2982int32 w = width;2983while (w--) {2984if (*pixels > 0) {2985uint16 color = activePalette[*pixels];2986setPixelAdditive(color, *frameBuffer);2987}2988++pixels;2989++frameBuffer;2990}2991frameBuffer += pitch;2992pixels += gfxPitch;2993}2994break;2995}29962997case INK_SUB: {2998uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];2999while (height--) {3000uint16 *activePalette = fullPalette[*lineBuffer];3001lineBuffer++;3002int32 w = width;3003while (w--) {3004if (*pixels > 0) {3005uint16 color = activePalette[*pixels];3006setPixelSubtractive(color, *frameBuffer);3007}3008++pixels;3009++frameBuffer;3010}3011frameBuffer += pitch;3012pixels += gfxPitch;3013}3014break;3015}30163017case INK_TINT:3018while (height--) {3019lineBuffer++;3020int32 w = width;3021while (w--) {3022if (*pixels > 0)3023*frameBuffer = tintLookupTable[*frameBuffer];3024++pixels;3025++frameBuffer;3026}3027frameBuffer += pitch;3028pixels += gfxPitch;3029}3030break;30313032case INK_MASKED:3033while (height--) {3034uint16 *activePalette = fullPalette[*lineBuffer];3035lineBuffer++;3036int32 w = width;3037while (w--) {3038if (*pixels > 0 && *frameBuffer == maskColor)3039*frameBuffer = activePalette[*pixels];3040++pixels;3041++frameBuffer;3042}3043frameBuffer += pitch;3044pixels += gfxPitch;3045}3046break;30473048case INK_UNMASKED:3049while (height--) {3050uint16 *activePalette = fullPalette[*lineBuffer];3051lineBuffer++;3052int32 w = width;3053while (w--) {3054if (*pixels > 0 && *frameBuffer != maskColor)3055*frameBuffer = activePalette[*pixels];3056++pixels;3057++frameBuffer;3058}3059frameBuffer += pitch;3060pixels += gfxPitch;3061}3062break;3063}3064break;30653066case FLIP_X:3067gfxPitch = width + surface->width;3068lineBuffer = &gfxLineBuffer[y];3069pixels = &surface->pixels[widthFlip - 1 + sprX + surface->width * sprY];3070frameBuffer = ¤tScreen->frameBuffer[x + currentScreen->pitch * y];3071switch (inkEffect) {3072case INK_NONE:3073while (height--) {3074uint16 *activePalette = fullPalette[*lineBuffer];3075lineBuffer++;3076int32 w = width;3077while (w--) {3078if (*pixels > 0)3079*frameBuffer = activePalette[*pixels];3080--pixels;3081++frameBuffer;3082}3083frameBuffer += pitch;3084pixels += gfxPitch;3085}3086break;30873088case INK_BLEND:3089while (height--) {3090uint16 *activePalette = fullPalette[*lineBuffer];3091lineBuffer++;3092int32 w = width;3093while (w--) {3094if (*pixels > 0)3095setPixelBlend(activePalette[*pixels], *frameBuffer);3096--pixels;3097++frameBuffer;3098}3099frameBuffer += pitch;3100pixels += gfxPitch;3101}3102break;31033104case INK_ALPHA: {3105uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];3106uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];31073108while (height--) {3109uint16 *activePalette = fullPalette[*lineBuffer];3110lineBuffer++;3111int32 w = width;3112while (w--) {3113if (*pixels > 0) {3114uint16 color = activePalette[*pixels];3115setPixelAlpha(color, *frameBuffer, alpha);3116}3117--pixels;3118++frameBuffer;3119}3120frameBuffer += pitch;3121pixels += gfxPitch;3122}3123break;3124}31253126case INK_ADD: {3127uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];3128while (height--) {3129uint16 *activePalette = fullPalette[*lineBuffer];3130lineBuffer++;3131int32 w = width;3132while (w--) {3133if (*pixels > 0) {3134uint16 color = activePalette[*pixels];3135setPixelAdditive(color, *frameBuffer);3136}3137--pixels;3138++frameBuffer;3139}3140frameBuffer += pitch;3141pixels += gfxPitch;3142}3143break;3144}31453146case INK_SUB: {3147uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];3148while (height--) {3149uint16 *activePalette = fullPalette[*lineBuffer];3150lineBuffer++;3151int32 w = width;3152while (w--) {3153if (*pixels > 0) {3154uint16 color = activePalette[*pixels];3155setPixelSubtractive(color, *frameBuffer);3156}3157--pixels;3158++frameBuffer;3159}3160frameBuffer += pitch;3161pixels += gfxPitch;3162}3163break;3164}31653166case INK_TINT:3167while (height--) {3168lineBuffer++;3169int32 w = width;3170while (w--) {3171if (*pixels > 0)3172*frameBuffer = tintLookupTable[*frameBuffer];3173--pixels;3174++frameBuffer;3175}3176frameBuffer += pitch;3177pixels += gfxPitch;3178}3179break;31803181case INK_MASKED:3182while (height--) {3183uint16 *activePalette = fullPalette[*lineBuffer];3184lineBuffer++;3185int32 w = width;3186while (w--) {3187if (*pixels > 0 && *frameBuffer == maskColor)3188*frameBuffer = activePalette[*pixels];3189--pixels;3190++frameBuffer;3191}3192frameBuffer += pitch;3193pixels += gfxPitch;3194}3195break;31963197case INK_UNMASKED:3198while (height--) {3199uint16 *activePalette = fullPalette[*lineBuffer];3200lineBuffer++;3201int32 w = width;3202while (w--) {3203if (*pixels > 0 && *frameBuffer != maskColor)3204*frameBuffer = activePalette[*pixels];3205--pixels;3206++frameBuffer;3207}3208frameBuffer += pitch;3209pixels += gfxPitch;3210}3211break;3212}3213break;32143215case FLIP_Y:3216gfxPitch = width + surface->width;3217lineBuffer = &gfxLineBuffer[y];3218pixels = &surface->pixels[sprX + surface->width * (sprY + heightFlip - 1)];3219frameBuffer = ¤tScreen->frameBuffer[x + currentScreen->pitch * y];3220switch (inkEffect) {3221case INK_NONE:3222while (height--) {3223uint16 *activePalette = fullPalette[*lineBuffer];3224lineBuffer++;3225int32 w = width;3226while (w--) {3227if (*pixels > 0)3228*frameBuffer = activePalette[*pixels];3229++pixels;3230++frameBuffer;3231}3232frameBuffer += pitch;3233pixels -= gfxPitch;3234}3235break;32363237case INK_BLEND:3238while (height--) {3239uint16 *activePalette = fullPalette[*lineBuffer];3240lineBuffer++;3241int32 w = width;3242while (w--) {3243if (*pixels > 0)3244setPixelBlend(activePalette[*pixels], *frameBuffer);3245++pixels;3246++frameBuffer;3247}3248frameBuffer += pitch;3249pixels -= gfxPitch;3250}3251break;32523253case INK_ALPHA: {3254uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];3255uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];32563257while (height--) {3258uint16 *activePalette = fullPalette[*lineBuffer];3259lineBuffer++;3260int32 w = width;3261while (w--) {3262if (*pixels > 0) {3263uint16 color = activePalette[*pixels];3264setPixelAlpha(color, *frameBuffer, alpha);3265}3266++pixels;3267++frameBuffer;3268}3269frameBuffer += pitch;3270pixels -= gfxPitch;3271}3272break;3273}32743275case INK_ADD: {3276uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];3277while (height--) {3278uint16 *activePalette = fullPalette[*lineBuffer];3279lineBuffer++;3280int32 w = width;3281while (w--) {3282if (*pixels > 0) {3283uint16 color = activePalette[*pixels];3284setPixelAdditive(color, *frameBuffer);3285}3286++pixels;3287++frameBuffer;3288}3289frameBuffer += pitch;3290pixels -= gfxPitch;3291}3292break;3293}32943295case INK_SUB: {3296uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];3297while (height--) {3298uint16 *activePalette = fullPalette[*lineBuffer];3299lineBuffer++;3300int32 w = width;3301while (w--) {3302if (*pixels > 0) {3303uint16 color = activePalette[*pixels];3304setPixelSubtractive(color, *frameBuffer);3305}3306++pixels;3307++frameBuffer;3308}3309frameBuffer += pitch;3310pixels -= gfxPitch;3311}3312break;3313}33143315case INK_TINT:3316while (height--) {3317lineBuffer++;3318int32 w = width;3319while (w--) {3320if (*pixels > 0)3321*frameBuffer = tintLookupTable[*frameBuffer];3322++pixels;3323++frameBuffer;3324}3325frameBuffer += pitch;3326pixels -= gfxPitch;3327}3328break;33293330case INK_MASKED:3331while (height--) {3332uint16 *activePalette = fullPalette[*lineBuffer];3333lineBuffer++;3334int32 w = width;3335while (w--) {3336if (*pixels > 0 && *frameBuffer == maskColor)3337*frameBuffer = activePalette[*pixels];3338++pixels;3339++frameBuffer;3340}3341frameBuffer += pitch;3342pixels -= gfxPitch;3343}3344break;33453346case INK_UNMASKED:3347while (height--) {3348uint16 *activePalette = fullPalette[*lineBuffer];3349lineBuffer++;3350int32 w = width;3351while (w--) {3352if (*pixels > 0 && *frameBuffer != maskColor)3353*frameBuffer = activePalette[*pixels];3354++pixels;3355++frameBuffer;3356}3357frameBuffer += pitch;3358pixels -= gfxPitch;3359}3360break;3361}3362break;33633364case FLIP_XY:3365gfxPitch = surface->width - width;3366lineBuffer = &gfxLineBuffer[y];3367pixels = &surface->pixels[widthFlip - 1 + sprX + surface->width * (sprY + heightFlip - 1)];3368frameBuffer = ¤tScreen->frameBuffer[x + currentScreen->pitch * y];3369switch (inkEffect) {3370case INK_NONE:3371while (height--) {3372uint16 *activePalette = fullPalette[*lineBuffer];3373lineBuffer++;3374int32 w = width;3375while (w--) {3376if (*pixels > 0)3377*frameBuffer = activePalette[*pixels];3378--pixels;3379++frameBuffer;3380}3381frameBuffer += pitch;3382pixels -= gfxPitch;3383}3384break;33853386case INK_BLEND:3387while (height--) {3388uint16 *activePalette = fullPalette[*lineBuffer];3389lineBuffer++;3390int32 w = width;3391while (w--) {3392if (*pixels > 0)3393setPixelBlend(activePalette[*pixels], *frameBuffer);3394--pixels;3395++frameBuffer;3396}3397frameBuffer += pitch;3398pixels -= gfxPitch;3399}3400break;34013402case INK_ALPHA: {3403uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];3404uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];34053406while (height--) {3407uint16 *activePalette = fullPalette[*lineBuffer];3408lineBuffer++;3409int32 w = width;3410while (w--) {3411if (*pixels > 0) {3412uint16 color = activePalette[*pixels];3413setPixelAlpha(color, *frameBuffer, alpha);3414}3415--pixels;3416++frameBuffer;3417}3418frameBuffer += pitch;3419pixels -= gfxPitch;3420}3421break;3422}34233424case INK_ADD: {3425uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];3426while (height--) {3427uint16 *activePalette = fullPalette[*lineBuffer];3428lineBuffer++;3429int32 w = width;3430while (w--) {3431if (*pixels > 0) {3432uint16 color = activePalette[*pixels];3433setPixelAdditive(color, *frameBuffer);3434}3435--pixels;3436++frameBuffer;3437}3438frameBuffer += pitch;3439pixels -= gfxPitch;3440}3441break;3442}34433444case INK_SUB: {3445uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];3446while (height--) {3447uint16 *activePalette = fullPalette[*lineBuffer];3448lineBuffer++;3449int32 w = width;3450while (w--) {3451if (*pixels > 0) {3452uint16 color = activePalette[*pixels];3453setPixelSubtractive(color, *frameBuffer);3454}3455--pixels;3456++frameBuffer;3457}3458frameBuffer += pitch;3459pixels -= gfxPitch;3460}3461break;3462}34633464case INK_TINT:3465while (height--) {3466lineBuffer++;3467int32 w = width;3468while (w--) {3469if (*pixels > 0)3470*frameBuffer = tintLookupTable[*frameBuffer];3471--pixels;3472++frameBuffer;3473}3474frameBuffer += pitch;3475pixels -= gfxPitch;3476}3477break;34783479case INK_MASKED:3480while (height--) {3481uint16 *activePalette = fullPalette[*lineBuffer];3482lineBuffer++;3483int32 w = width;3484while (w--) {3485if (*pixels > 0 && *frameBuffer == maskColor)3486*frameBuffer = activePalette[*pixels];3487--pixels;3488++frameBuffer;3489}3490frameBuffer += pitch;3491pixels -= gfxPitch;3492}3493break;34943495case INK_UNMASKED:3496while (height--) {3497uint16 *activePalette = fullPalette[*lineBuffer];3498lineBuffer++;3499int32 w = width;3500while (w--) {3501if (*pixels > 0 && *frameBuffer != maskColor)3502*frameBuffer = activePalette[*pixels];3503--pixels;3504++frameBuffer;3505}3506frameBuffer += pitch;3507pixels -= gfxPitch;3508}3509break;3510}3511break;3512}3513}3514void RSDK::DrawSpriteRotozoom(int32 x, int32 y, int32 pivotX, int32 pivotY, int32 width, int32 height, int32 sprX, int32 sprY, int32 scaleX,3515int32 scaleY, int32 direction, int16 rotation, int32 inkEffect, int32 alpha, int32 sheetID)3516{3517switch (inkEffect) {3518default: break;3519case INK_ALPHA:3520if (alpha > 0xFF)3521inkEffect = INK_NONE;3522else if (alpha <= 0)3523return;3524break;35253526case INK_ADD:3527case INK_SUB:3528if (alpha > 0xFF)3529alpha = 0xFF;3530else if (alpha <= 0)3531return;3532break;35333534case INK_TINT:3535if (!tintLookupTable)3536return;3537break;3538}35393540int32 angle = 0x200 - (rotation & 0x1FF);3541if (!(rotation & 0x1FF))3542angle = rotation & 0x1FF;35433544int32 sine = sin512LookupTable[angle];3545int32 cosine = cos512LookupTable[angle];3546int32 fullScaleXS = scaleX * sine >> 9;3547int32 fullScaleXC = scaleX * cosine >> 9;3548int32 fullScaleYS = scaleY * sine >> 9;3549int32 fullScaleYC = scaleY * cosine >> 9;35503551int32 posX[4];3552int32 posY[4];3553int32 sprXPos = TO_FIXED(sprX - pivotX);3554int32 sprYPos = TO_FIXED(sprY - pivotY);35553556int32 xMax = 0;3557int32 scaledX1 = 0;3558int32 scaledX2 = 0;3559int32 scaledY1 = 0;3560int32 scaledY2 = 0;3561switch (direction) {3562default:3563case FLIP_NONE: {3564scaledX1 = fullScaleXS * (pivotX - 2);3565scaledX2 = fullScaleXC * (pivotX - 2);3566scaledY1 = fullScaleYS * (pivotY - 2);3567scaledY2 = fullScaleYC * (pivotY - 2);3568xMax = pivotX + 2 + width;3569posX[0] = x + ((scaledX2 + scaledY1) >> 9);3570posY[0] = y + ((fullScaleYC * (pivotY - 2) - scaledX1) >> 9);3571break;3572}35733574case FLIP_X: {3575scaledX1 = fullScaleXS * (2 - pivotX);3576scaledX2 = fullScaleXC * (2 - pivotX);3577scaledY1 = fullScaleYS * (pivotY - 2);3578scaledY2 = fullScaleYC * (pivotY - 2);3579xMax = -2 - pivotX - width;3580posX[0] = x + ((scaledX2 + scaledY1) >> 9);3581posY[0] = y + ((fullScaleYC * (pivotY - 2) - scaledX1) >> 9);3582break;3583}35843585case FLIP_Y:3586case FLIP_XY: break;3587}35883589int32 scaledXMaxS = fullScaleXS * xMax;3590int32 scaledXMaxC = fullScaleXC * xMax;3591int32 scaledYMaxC = fullScaleYC * (pivotY + 2 + height);3592int32 scaledYMaxS = fullScaleYS * (pivotY + 2 + height);3593posX[1] = x + ((scaledXMaxC + scaledY1) >> 9);3594posY[1] = y + ((scaledY2 - scaledXMaxS) >> 9);3595posX[2] = x + ((scaledYMaxS + scaledX2) >> 9);3596posY[2] = y + ((scaledYMaxC - scaledX1) >> 9);3597posX[3] = x + ((scaledXMaxC + scaledYMaxS) >> 9);3598posY[3] = y + ((scaledYMaxC - scaledXMaxS) >> 9);35993600int32 left = currentScreen->pitch;3601for (int32 i = 0; i < 4; ++i) {3602if (posX[i] < left)3603left = posX[i];3604}3605if (left < currentScreen->clipBound_X1)3606left = currentScreen->clipBound_X1;36073608int32 right = 0;3609for (int32 i = 0; i < 4; ++i) {3610if (posX[i] > right)3611right = posX[i];3612}3613if (right > currentScreen->clipBound_X2)3614right = currentScreen->clipBound_X2;36153616int32 top = currentScreen->size.y;3617for (int32 i = 0; i < 4; ++i) {3618if (posY[i] < top)3619top = posY[i];3620}3621if (top < currentScreen->clipBound_Y1)3622top = currentScreen->clipBound_Y1;36233624int32 bottom = 0;3625for (int32 i = 0; i < 4; ++i) {3626if (posY[i] > bottom)3627bottom = posY[i];3628}3629if (bottom > currentScreen->clipBound_Y2)3630bottom = currentScreen->clipBound_Y2;36313632int32 xSize = right - left;3633int32 ySize = bottom - top;3634if (xSize >= 1 && ySize >= 1) {3635GFXSurface *surface = &gfxSurface[sheetID];36363637int32 fullX = TO_FIXED(sprX + width);3638int32 fullY = TO_FIXED(sprY + height);3639validDraw = true;3640int32 fullScaleX = (int32)((512.0 / (float)scaleX) * 512.0);3641int32 fullScaleY = (int32)((512.0 / (float)scaleY) * 512.0);3642int32 deltaXLen = fullScaleX * sine >> 2;3643int32 deltaX = fullScaleX * cosine >> 2;3644int32 pitch = currentScreen->pitch - xSize;3645int32 deltaYLen = fullScaleY * cosine >> 2;3646int32 deltaY = fullScaleY * sine >> 2;3647int32 lineSize = surface->lineSize;3648uint8 *lineBuffer = &gfxLineBuffer[top];3649int32 xLen = left - x;3650int32 yLen = top - y;3651uint8 *pixels = surface->pixels;3652uint16 *frameBuffer = ¤tScreen->frameBuffer[left + (top * currentScreen->pitch)];3653int32 fullSprX = TO_FIXED(sprX) - 1;3654int32 fullSprY = TO_FIXED(sprY) - 1;36553656int32 drawX = 0, drawY = 0;3657if (direction == FLIP_X) {3658drawX = sprXPos + deltaXLen * yLen - deltaX * xLen - (fullScaleX >> 1);3659drawY = sprYPos + deltaYLen * yLen + deltaY * xLen;3660deltaX = -deltaX;3661deltaXLen = -deltaXLen;3662}3663else if (!direction) {3664drawX = sprXPos + deltaX * xLen - deltaXLen * yLen;3665drawY = sprYPos + deltaYLen * yLen + deltaY * xLen;3666}36673668switch (inkEffect) {3669case INK_NONE:3670for (int32 y = 0; y < ySize; ++y) {3671uint16 *activePalette = fullPalette[*lineBuffer++];3672int32 drawXPos = drawX;3673int32 drawYPos = drawY;3674for (int32 x = 0; x < xSize; ++x) {3675if (drawXPos >= fullSprX && drawXPos < fullX && drawYPos >= fullSprY && drawYPos < fullY) {3676uint8 index = pixels[(FROM_FIXED(drawYPos) << lineSize) + FROM_FIXED(drawXPos)];3677if (index)3678*frameBuffer = activePalette[index];3679}36803681++frameBuffer;3682drawXPos += deltaX;3683drawYPos += deltaY;3684}36853686drawX -= deltaXLen;3687drawY += deltaYLen;3688frameBuffer += pitch;3689}3690break;36913692case INK_BLEND:3693for (int32 y = 0; y < ySize; ++y) {3694uint16 *activePalette = fullPalette[*lineBuffer++];3695int32 drawXPos = drawX;3696int32 drawYPos = drawY;3697for (int32 x = 0; x < xSize; ++x) {3698if (drawXPos >= fullSprX && drawXPos < fullX && drawYPos >= fullSprY && drawYPos < fullY) {3699uint8 index = pixels[(FROM_FIXED(drawYPos) << lineSize) + FROM_FIXED(drawXPos)];3700if (index)3701setPixelBlend(activePalette[index], *frameBuffer);3702}37033704++frameBuffer;3705drawXPos += deltaX;3706drawYPos += deltaY;3707}37083709drawX -= deltaXLen;3710drawY += deltaYLen;3711frameBuffer += pitch;3712}3713break;37143715case INK_ALPHA: {3716uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];3717uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];37183719for (int32 y = 0; y < ySize; ++y) {3720uint16 *activePalette = fullPalette[*lineBuffer++];3721int32 drawXPos = drawX;3722int32 drawYPos = drawY;3723for (int32 x = 0; x < xSize; ++x) {3724if (drawXPos >= fullSprX && drawXPos < fullX && drawYPos >= fullSprY && drawYPos < fullY) {3725uint8 index = pixels[(FROM_FIXED(drawYPos) << lineSize) + FROM_FIXED(drawXPos)];3726if (index) {3727setPixelAlpha(activePalette[index], *frameBuffer, alpha);3728}3729}37303731++frameBuffer;3732drawXPos += deltaX;3733drawYPos += deltaY;3734}37353736drawX -= deltaXLen;3737drawY += deltaYLen;3738frameBuffer += pitch;3739}3740break;3741}37423743case INK_ADD: {3744uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];3745for (int32 y = 0; y < ySize; ++y) {3746uint16 *activePalette = fullPalette[*lineBuffer++];3747int32 drawXPos = drawX;3748int32 drawYPos = drawY;3749for (int32 x = 0; x < xSize; ++x) {3750if (drawXPos >= fullSprX && drawXPos < fullX && drawYPos >= fullSprY && drawYPos < fullY) {3751uint8 index = pixels[(FROM_FIXED(drawYPos) << lineSize) + FROM_FIXED(drawXPos)];3752if (index) {3753setPixelAdditive(activePalette[index], *frameBuffer);3754}3755}37563757++frameBuffer;3758drawXPos += deltaX;3759drawYPos += deltaY;3760}37613762drawX -= deltaXLen;3763drawY += deltaYLen;3764frameBuffer += pitch;3765}3766break;3767}37683769case INK_SUB: {3770uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];3771for (int32 y = 0; y < ySize; ++y) {3772uint16 *activePalette = fullPalette[*lineBuffer++];3773int32 drawXPos = drawX;3774int32 drawYPos = drawY;3775for (int32 x = 0; x < xSize; ++x) {3776if (drawXPos >= fullSprX && drawXPos < fullX && drawYPos >= fullSprY && drawYPos < fullY) {3777uint8 index = pixels[(FROM_FIXED(drawYPos) << lineSize) + FROM_FIXED(drawXPos)];3778if (index) {3779setPixelSubtractive(activePalette[index], *frameBuffer);3780}3781}37823783++frameBuffer;3784drawXPos += deltaX;3785drawYPos += deltaY;3786}37873788drawX -= deltaXLen;3789drawY += deltaYLen;3790frameBuffer += pitch;3791}3792break;3793}37943795case INK_TINT:3796for (int32 y = 0; y < ySize; ++y) {3797int32 drawXPos = drawX;3798int32 drawYPos = drawY;3799for (int32 x = 0; x < xSize; ++x) {3800if (drawXPos >= fullSprX && drawXPos < fullX && drawYPos >= fullSprY && drawYPos < fullY) {3801uint8 index = pixels[(FROM_FIXED(drawYPos) << lineSize) + FROM_FIXED(drawXPos)];3802if (index)3803*frameBuffer = tintLookupTable[*frameBuffer];3804}38053806++frameBuffer;3807drawXPos += deltaX;3808drawYPos += deltaY;3809}38103811drawX -= deltaXLen;3812drawY += deltaYLen;3813frameBuffer += pitch;3814}3815break;38163817case INK_MASKED:3818for (int32 y = 0; y < ySize; ++y) {3819uint16 *activePalette = fullPalette[*lineBuffer++];3820int32 drawXPos = drawX;3821int32 drawYPos = drawY;3822for (int32 x = 0; x < xSize; ++x) {3823if (drawXPos >= fullSprX && drawXPos < fullX && drawYPos >= fullSprY && drawYPos < fullY) {3824uint8 index = pixels[(FROM_FIXED(drawYPos) << lineSize) + FROM_FIXED(drawXPos)];3825if (index && *frameBuffer == maskColor)3826*frameBuffer = activePalette[index];3827}38283829++frameBuffer;3830drawXPos += deltaX;3831drawYPos += deltaY;3832}38333834drawX -= deltaXLen;3835drawY += deltaYLen;3836frameBuffer += pitch;3837}3838break;38393840case INK_UNMASKED:3841for (int32 y = 0; y < ySize; ++y) {3842uint16 *activePalette = fullPalette[*lineBuffer++];3843int32 drawXPos = drawX;3844int32 drawYPos = drawY;3845for (int32 x = 0; x < xSize; ++x) {3846if (drawXPos >= fullSprX && drawXPos < fullX && drawYPos >= fullSprY && drawYPos < fullY) {3847uint8 index = pixels[(FROM_FIXED(drawYPos) << lineSize) + FROM_FIXED(drawXPos)];3848if (index && *frameBuffer != maskColor)3849*frameBuffer = activePalette[index];3850}38513852++frameBuffer;3853drawXPos += deltaX;3854drawYPos += deltaY;3855}38563857drawX -= deltaXLen;3858drawY += deltaYLen;3859frameBuffer += pitch;3860}3861break;3862}3863}3864}38653866void RSDK::DrawDeformedSprite(uint16 sheetID, int32 inkEffect, int32 alpha)3867{3868switch (inkEffect) {3869default: break;3870case INK_ALPHA:3871if (alpha > 0xFF)3872inkEffect = INK_NONE;3873else if (alpha <= 0)3874return;3875break;38763877case INK_ADD:3878case INK_SUB:3879if (alpha > 0xFF)3880alpha = 0xFF;3881else if (alpha <= 0)3882return;3883break;38843885case INK_TINT:3886if (!tintLookupTable)3887return;3888break;3889}38903891validDraw = true;3892GFXSurface *surface = &gfxSurface[sheetID];3893uint8 *pixels = surface->pixels;3894int32 clipY1 = currentScreen->clipBound_Y1;3895ScanlineInfo *scanline = &scanlines[clipY1];3896uint16 *frameBuffer = ¤tScreen->frameBuffer[clipY1 * currentScreen->pitch];3897uint8 *lineBuffer = &gfxLineBuffer[clipY1];3898int32 width = surface->width - 1;3899int32 height = surface->height - 1;3900int32 lineSize = surface->lineSize;39013902switch (inkEffect) {3903case INK_NONE:3904for (; clipY1 < currentScreen->clipBound_Y2; ++clipY1) {3905uint16 *activePalette = fullPalette[*lineBuffer++];3906int32 lx = scanline->position.x;3907int32 ly = scanline->position.y;3908int32 dx = scanline->deform.x;3909int32 dy = scanline->deform.y;3910for (int32 i = 0; i < currentScreen->pitch; ++i) {3911uint8 palIndex = pixels[((FROM_FIXED(ly) & height) << lineSize) + (FROM_FIXED(lx) & width)];3912if (palIndex)3913*frameBuffer = activePalette[palIndex];39143915lx += dx;3916ly += dy;3917++frameBuffer;3918}3919++scanline;3920}3921break;39223923case INK_BLEND:3924for (; clipY1 < currentScreen->clipBound_Y2; ++clipY1) {3925uint16 *activePalette = fullPalette[*lineBuffer++];3926int32 lx = scanline->position.x;3927int32 ly = scanline->position.y;3928int32 dx = scanline->deform.x;3929int32 dy = scanline->deform.y;3930for (int32 i = 0; i < currentScreen->pitch; ++i) {3931uint8 palIndex = pixels[((FROM_FIXED(ly) & height) << lineSize) + (FROM_FIXED(lx) & width)];3932if (palIndex)3933setPixelBlend(activePalette[palIndex], *frameBuffer);39343935lx += dx;3936ly += dy;3937++frameBuffer;3938}3939++scanline;3940}3941break;39423943case INK_ALPHA: {3944uint16 *fbufferBlend = &blendLookupTable[0x20 * (0xFF - alpha)];3945uint16 *pixelBlend = &blendLookupTable[0x20 * alpha];39463947for (; clipY1 < currentScreen->clipBound_Y2; ++clipY1) {3948uint16 *activePalette = fullPalette[*lineBuffer++];3949int32 lx = scanline->position.x;3950int32 ly = scanline->position.y;3951int32 dx = scanline->deform.x;3952int32 dy = scanline->deform.y;3953for (int32 i = 0; i < currentScreen->pitch; ++i) {3954uint8 palIndex = pixels[((FROM_FIXED(ly) & height) << lineSize) + (FROM_FIXED(lx) & width)];3955if (palIndex) {3956setPixelAlpha(activePalette[palIndex], *frameBuffer, alpha);3957}39583959lx += dx;3960ly += dy;3961++frameBuffer;3962}3963++scanline;3964}3965break;3966}39673968case INK_ADD: {3969uint16 *blendTablePtr = &blendLookupTable[0x20 * alpha];39703971for (; clipY1 < currentScreen->clipBound_Y2; ++clipY1) {3972uint16 *activePalette = fullPalette[*lineBuffer++];3973int32 lx = scanline->position.x;3974int32 ly = scanline->position.y;3975int32 dx = scanline->deform.x;3976int32 dy = scanline->deform.y;3977for (int32 i = 0; i < currentScreen->pitch; ++i) {3978uint8 palIndex = pixels[((FROM_FIXED(ly) & height) << lineSize) + (FROM_FIXED(lx) & width)];3979if (palIndex) {3980setPixelAdditive(activePalette[palIndex], *frameBuffer);3981}39823983lx += dx;3984ly += dy;3985++frameBuffer;3986}3987++scanline;3988}3989break;3990}39913992case INK_SUB: {3993uint16 *subBlendTable = &subtractLookupTable[0x20 * alpha];39943995for (; clipY1 < currentScreen->clipBound_Y2; ++clipY1) {3996uint16 *activePalette = fullPalette[*lineBuffer++];3997int32 lx = scanline->position.x;3998int32 ly = scanline->position.y;3999int32 dx = scanline->deform.x;4000int32 dy = scanline->deform.y;4001for (int32 i = 0; i < currentScreen->pitch; ++i) {4002uint8 palIndex = pixels[((FROM_FIXED(ly) & height) << lineSize) + (FROM_FIXED(lx) & width)];4003if (palIndex) {4004setPixelSubtractive(activePalette[palIndex], *frameBuffer);4005}4006lx += dx;4007ly += dy;4008++frameBuffer;4009}4010++scanline;4011}4012break;4013}40144015case INK_TINT:4016for (; clipY1 < currentScreen->clipBound_Y2; ++clipY1) {4017int32 lx = scanline->position.x;4018int32 ly = scanline->position.y;4019int32 dx = scanline->deform.x;4020int32 dy = scanline->deform.y;4021for (int32 i = 0; i < currentScreen->pitch; ++i) {4022uint8 palIndex = pixels[((FROM_FIXED(ly) & height) << lineSize) + (FROM_FIXED(lx) & width)];4023if (palIndex)4024*frameBuffer = tintLookupTable[*frameBuffer];4025lx += dx;4026ly += dy;4027++frameBuffer;4028}4029++scanline;4030}4031break;40324033case INK_MASKED:4034for (; clipY1 < currentScreen->clipBound_Y2; ++clipY1) {4035uint16 *activePalette = fullPalette[*lineBuffer++];4036int32 lx = scanline->position.x;4037int32 ly = scanline->position.y;4038int32 dx = scanline->deform.x;4039int32 dy = scanline->deform.y;4040for (int32 i = 0; i < currentScreen->pitch; ++i) {4041uint8 palIndex = pixels[((FROM_FIXED(ly) & height) << lineSize) + (FROM_FIXED(lx) & width)];4042if (palIndex && *frameBuffer == maskColor)4043*frameBuffer = activePalette[palIndex];4044lx += dx;4045ly += dy;4046++frameBuffer;4047}4048++scanline;4049}4050break;40514052case INK_UNMASKED:4053for (; clipY1 < currentScreen->clipBound_Y2; ++clipY1) {4054uint16 *activePalette = fullPalette[*lineBuffer++];4055int32 lx = scanline->position.x;4056int32 ly = scanline->position.y;4057int32 dx = scanline->deform.x;4058int32 dy = scanline->deform.y;4059for (int32 i = 0; i < currentScreen->pitch; ++i) {4060uint8 palIndex = pixels[((FROM_FIXED(ly) & height) << lineSize) + (FROM_FIXED(lx) & width)];4061if (palIndex && *frameBuffer != maskColor)4062*frameBuffer = activePalette[palIndex];4063lx += dx;4064ly += dy;4065++frameBuffer;4066}4067++scanline;4068}4069break;4070}4071}40724073void RSDK::DrawTile(uint16 *tiles, int32 countX, int32 countY, Vector2 *position, Vector2 *offset, bool32 screenRelative)4074{4075if (tiles) {4076if (!position)4077position = &sceneInfo.entity->position;40784079int32 x = FROM_FIXED(position->x);4080int32 y = FROM_FIXED(position->y);4081if (!screenRelative) {4082x -= currentScreen->position.x;4083y -= currentScreen->position.y;4084}40854086int32 pivotX = 0;4087int32 pivotY = 0;4088switch (sceneInfo.entity->drawFX) {4089case FX_NONE:4090case FX_FLIP:4091if (offset) {4092pivotX = x - (offset->x >> 17);4093pivotY = y - (offset->y >> 17);4094}4095else {4096pivotX = x - (countX * (TILE_SIZE >> 1));4097pivotY = y - (countY * (TILE_SIZE >> 1));4098}40994100for (int32 ty = 0; ty < countY; ++ty) {4101for (int32 tx = 0; tx < countX; ++tx) {4102uint16 tile = tiles[tx + (ty * countX)];4103if (tile < 0xFFFF) {4104DrawSpriteFlipped((tx * TILE_SIZE) + pivotX, (ty * TILE_SIZE) + pivotY, TILE_SIZE, TILE_SIZE, 0,4105TILE_SIZE * (tile & 0xFFF), FLIP_NONE, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4106}4107}4108}4109break;41104111case FX_ROTATE: // Flip4112case FX_ROTATE | FX_FLIP:4113if (offset) {4114pivotX = -(offset->x >> 17);4115pivotY = -(offset->y >> 17);4116}4117else {4118pivotX = -(countX * (TILE_SIZE >> 1));4119pivotY = -(countY * (TILE_SIZE >> 1));4120}41214122for (int32 ty = 0; ty < countY; ++ty) {4123for (int32 tx = 0; tx < countX; ++tx) {4124uint16 tile = tiles[tx + (ty * countX)];4125if (tile < 0xFFFF) {4126switch ((tile >> 10) & 3) {4127case FLIP_NONE:4128DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4129TILE_SIZE * (tile & 0x3FF), 0x200, 0x200, FLIP_NONE, sceneInfo.entity->rotation,4130sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4131break;41324133case FLIP_X:4134DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4135TILE_SIZE * (tile & 0x3FF), 0x200, 0x200, FLIP_X, sceneInfo.entity->rotation,4136sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4137break;41384139case FLIP_Y:4140DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4141TILE_SIZE * (tile & 0x3FF), 0x200, 0x200, FLIP_X, sceneInfo.entity->rotation + 0x100,4142sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4143break;41444145case FLIP_XY:4146DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4147TILE_SIZE * (tile & 0x3FF), 0x200, 0x200, FLIP_NONE, sceneInfo.entity->rotation + 0x100,4148sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4149break;4150}4151}4152}4153}4154break;41554156case FX_SCALE: // Scale4157case FX_SCALE | FX_FLIP:4158if (offset) {4159pivotX = -(offset->x >> 17);4160pivotY = -(offset->y >> 17);4161}4162else {4163pivotX = -(countX * (TILE_SIZE >> 1));4164pivotY = -(countY * (TILE_SIZE >> 1));4165}41664167for (int32 ty = 0; ty < countY; ++ty) {4168for (int32 tx = 0; tx < countX; ++tx) {4169uint16 tile = tiles[tx + (ty * countX)];4170if (tile < 0xFFFF) {4171switch ((tile >> 10) & 3) {4172case FLIP_NONE:4173DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4174TILE_SIZE * (tile & 0x3FF), sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_NONE,41750x000, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4176break;41774178case FLIP_X:4179DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4180TILE_SIZE * (tile & 0x3FF), sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_X,41810x000, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4182break;41834184case FLIP_Y:4185DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4186TILE_SIZE * (tile & 0x3FF), sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_X,41870x100, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4188break;41894190case FLIP_XY:4191DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4192TILE_SIZE * (tile & 0x3FF), sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_NONE,41930x100, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4194break;4195}4196}4197}4198}4199break;42004201case FX_SCALE | FX_ROTATE: // Flip + Scale + Rotation4202case FX_SCALE | FX_ROTATE | FX_FLIP:4203if (offset) {4204pivotX = -(offset->x >> 17);4205pivotY = -(offset->y >> 17);4206}4207else {4208pivotX = -(countX * (TILE_SIZE >> 1));4209pivotY = -(countY * (TILE_SIZE >> 1));4210}42114212for (int32 ty = 0; ty < countY; ++ty) {4213for (int32 tx = 0; tx < countX; ++tx) {4214uint16 tile = tiles[tx + (ty * countX)];4215if (tile < 0xFFFF) {4216switch ((tile >> 10) & 3) {4217case FLIP_NONE:4218DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4219TILE_SIZE * (tile & 0x3FF), sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_NONE,4220sceneInfo.entity->rotation, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4221break;42224223case FLIP_X:4224DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4225TILE_SIZE * (tile & 0x3FF), sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_X,4226sceneInfo.entity->rotation, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4227break;42284229case FLIP_Y:4230DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4231TILE_SIZE * (tile & 0x3FF), sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_X,4232sceneInfo.entity->rotation + 0x100, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4233break;42344235case FLIP_XY:4236DrawSpriteRotozoom(x + (tx * TILE_SIZE), y + (ty * TILE_SIZE), pivotX, pivotY, TILE_SIZE, TILE_SIZE, 0,4237TILE_SIZE * (tile & 0x3FF), sceneInfo.entity->scale.x, sceneInfo.entity->scale.y, FLIP_NONE,4238sceneInfo.entity->rotation + 0x100, sceneInfo.entity->inkEffect, sceneInfo.entity->alpha, 0);4239break;4240}4241}4242}4243}4244break;4245}4246}4247}4248void RSDK::DrawAniTile(uint16 sheetID, uint16 tileIndex, uint16 srcX, uint16 srcY, uint16 width, uint16 height)4249{42504251if (sheetID < SURFACE_COUNT && tileIndex < TILE_COUNT) {4252GFXSurface *surface = &gfxSurface[sheetID];42534254// FLIP_NONE4255uint8 *tilePixels = &tilesetPixels[tileIndex << 8];4256int32 cnt = 0;4257for (int32 fy = 0; fy < height; fy += TILE_SIZE) {4258uint8 *pixels = &surface->pixels[((fy + srcY) << surface->lineSize) + srcX];4259cnt += ((width - 1) / TILE_SIZE) + 1;4260for (int32 fx = 0; fx < width; fx += TILE_SIZE) {4261uint8 *pixelsPtr = &pixels[fx];4262for (int32 ty = 0; ty < TILE_SIZE; ++ty) {4263for (int32 tx = 0; tx < TILE_SIZE; ++tx) *tilePixels++ = *pixelsPtr++;42644265pixelsPtr += surface->width - TILE_SIZE;4266}4267}4268}42694270// FLIP_X4271uint8 *srcTilePixels = &tilesetPixels[tileIndex << 8];4272if (cnt * TILE_SIZE > 0) {4273tilePixels = &tilesetPixels[(tileIndex << 8) + (FLIP_X * TILESET_SIZE) + (TILE_SIZE - 1)];42744275for (int32 i = 0; i < cnt * TILE_SIZE; ++i) {4276for (int32 p = 0; p < TILE_SIZE; ++p) *tilePixels-- = *srcTilePixels++;42774278tilePixels += (TILE_SIZE * 2);4279}4280}42814282// FLIP_Y4283srcTilePixels = &tilesetPixels[tileIndex << 8];4284if (cnt * TILE_SIZE > 0) {4285int32 index = tileIndex;4286for (int32 i = 0; i < cnt; ++i) {4287tilePixels = &tilesetPixels[(index << 8) + (FLIP_Y * TILESET_SIZE) + (TILE_DATASIZE - TILE_SIZE)];4288for (int32 y = 0; y < TILE_SIZE; ++y) {4289for (int32 x = 0; x < TILE_SIZE; ++x) *tilePixels++ = *srcTilePixels++;42904291tilePixels -= (TILE_SIZE * 2);4292}4293++index;4294}4295}42964297// FLIP_XY4298srcTilePixels = &tilesetPixels[(tileIndex << 8) + (FLIP_Y * TILESET_SIZE)];4299if (cnt * TILE_SIZE > 0) {4300tilePixels = &tilesetPixels[(tileIndex << 8) + (FLIP_XY * TILESET_SIZE) + (TILE_SIZE - 1)];43014302for (int32 i = 0; i < cnt * TILE_SIZE; ++i) {4303for (int32 p = 0; p < TILE_SIZE; ++p) *tilePixels-- = *srcTilePixels++;43044305tilePixels += (TILE_SIZE * 2);4306}4307}4308}4309}43104311void RSDK::DrawString(Animator *animator, Vector2 *position, String *string, int32 startFrame, int32 endFrame, int32 align, int32 spacing,4312void *unused, Vector2 *charOffsets, bool32 screenRelative)4313{4314if (animator && string && animator->frames) {4315if (!position)4316position = &sceneInfo.entity->position;43174318Entity *entity = sceneInfo.entity;43194320int32 x = FROM_FIXED(position->x);4321int32 y = FROM_FIXED(position->y);4322if (!screenRelative) {4323x -= currentScreen->position.x;4324y -= currentScreen->position.y;4325}43264327startFrame = CLAMP(startFrame, 0, string->length - 1);43284329if (endFrame <= 0 || endFrame > string->length)4330endFrame = string->length;43314332switch (align) {4333case ALIGN_LEFT:4334if (charOffsets) {4335for (; startFrame < endFrame; ++startFrame) {4336uint16 curChar = string->chars[startFrame];4337if (curChar < animator->frameCount) {4338SpriteFrame *frame = &animator->frames[curChar];4339DrawSpriteFlipped(x + FROM_FIXED(charOffsets->x), y + frame->pivotY + FROM_FIXED(charOffsets->y), frame->width,4340frame->height, frame->sprX, frame->sprY, FLIP_NONE, entity->inkEffect, entity->alpha, frame->sheetID);4341x += spacing + frame->width;4342++charOffsets;4343}4344}4345}4346else {4347for (; startFrame < endFrame; ++startFrame) {4348uint16 curChar = string->chars[startFrame];4349if (curChar < animator->frameCount) {4350SpriteFrame *frame = &animator->frames[curChar];4351DrawSpriteFlipped(x, y + frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY, FLIP_NONE,4352entity->inkEffect, entity->alpha, frame->sheetID);4353x += spacing + frame->width;4354}4355}4356}4357break;43584359case ALIGN_RIGHT: break;43604361case ALIGN_CENTER:4362--endFrame;4363if (charOffsets) {4364for (Vector2 *charOffset = &charOffsets[endFrame]; endFrame >= startFrame; --endFrame) {4365uint16 curChar = string->chars[endFrame];4366if (curChar < animator->frameCount) {4367SpriteFrame *frame = &animator->frames[curChar];4368DrawSpriteFlipped(x - frame->width + FROM_FIXED(charOffset->x), y + frame->pivotY + FROM_FIXED(charOffset->y),4369frame->width, frame->height, frame->sprX, frame->sprY, FLIP_NONE, entity->inkEffect, entity->alpha,4370frame->sheetID);4371x = (x - frame->width) - spacing;4372--charOffset;4373}4374}4375}4376else {4377for (; endFrame >= startFrame; --endFrame) {4378uint16 curChar = string->chars[endFrame];4379if (curChar < animator->frameCount) {4380SpriteFrame *frame = &animator->frames[curChar];4381DrawSpriteFlipped(x - frame->width, y + frame->pivotY, frame->width, frame->height, frame->sprX, frame->sprY, FLIP_NONE,4382entity->inkEffect, entity->alpha, frame->sheetID);4383x = (x - frame->width) - spacing;4384}4385}4386}4387break;4388}4389}4390}4391void RSDK::DrawDevString(const char *string, int32 x, int32 y, int32 align, uint32 color)4392{4393uint16 color16 = rgb32To16_B[(color >> 0) & 0xFF] | rgb32To16_G[(color >> 8) & 0xFF] | rgb32To16_R[(color >> 16) & 0xFF];43944395int32 charOffset = 0;4396bool32 linesRemain = true;4397while (linesRemain) {4398linesRemain = false;43994400int32 lineSize = 0;4401char cur = string[charOffset];4402if (cur != '\n') {4403while (cur) {4404cur = string[++charOffset];4405lineSize++;4406if (cur == '\n') {4407linesRemain = true;4408break;4409}4410}4411}44124413if (y >= 0 && y < currentScreen->size.y - 7) {4414int32 offset = 0;4415switch (align) {4416default:4417case ALIGN_LEFT: offset = 0; break;44184419case ALIGN_CENTER: offset = 4 * lineSize; break;44204421case ALIGN_RIGHT: offset = 8 * lineSize; break;4422}4423int32 drawX = x - offset;44244425const char *curChar = &string[charOffset++ - lineSize];44264427for (int32 c = 0; c < lineSize; ++c) {4428if (drawX >= 0 && drawX < currentScreen->size.x - 7) {4429uint16 *frameBuffer = ¤tScreen->frameBuffer[drawX + y * currentScreen->pitch];44304431if ((*curChar < '\t' || *curChar > '\n') && *curChar != ' ') {4432uint8 *textStencilPtr = &devTextStencil[0x40 * *curChar];44334434for (int32 h = 0; h < 8; ++h) {4435for (int32 w = 0; w < 8; ++w) {4436if (*textStencilPtr)4437*frameBuffer = color16;44384439++textStencilPtr;4440++frameBuffer;4441}44424443frameBuffer += currentScreen->pitch - 8;4444}4445}44464447++curChar;4448drawX += 8;4449}4450}4451}44524453y += 8;4454}4455}445644574458