#include "svga.h" #include #include #include #include "config.h" #include "draw.h" #include "interface.h" #include "memory.h" #include "mouse.h" #include "win32.h" #include "window_manager.h" #include "window_manager_private.h" namespace fallout { static bool createRenderer(int width, int height); static void destroyRenderer(); // screen rect Rect _scr_size; // 0x6ACA18 void (*_scr_blit)(unsigned char* src, int src_pitch, int a3, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y) = _GNW95_ShowRect; // 0x6ACA1C void (*_zero_mem)() = NULL; SDL_Window* gSdlWindow = NULL; SDL_Surface* gSdlSurface = NULL; SDL_Renderer* gSdlRenderer = NULL; SDL_Texture* gSdlTexture = NULL; SDL_Surface* gSdlTextureSurface = NULL; // TODO: Remove once migration to update-render cycle is completed. FpsLimiter sharedFpsLimiter; // 0x4CAD08 int _init_mode_320_200() { return _GNW95_init_mode_ex(320, 200, 8); } // 0x4CAD40 int _init_mode_320_400() { return _GNW95_init_mode_ex(320, 400, 8); } // 0x4CAD5C int _init_mode_640_480_16() { return -1; } // 0x4CAD64 int _init_mode_640_480() { return _init_vesa_mode(640, 480); } // 0x4CAD94 int _init_mode_640_400() { return _init_vesa_mode(640, 400); } // 0x4CADA8 int _init_mode_800_600() { return _init_vesa_mode(800, 600); } // 0x4CADBC int _init_mode_1024_768() { return _init_vesa_mode(1024, 768); } // 0x4CADD0 int _init_mode_1280_1024() { return _init_vesa_mode(1280, 1024); } // 0x4CADF8 void _get_start_mode_() { } // 0x4CADFC void _zero_vid_mem() { if (_zero_mem) { _zero_mem(); } } // 0x4CAE1C int _GNW95_init_mode_ex(int width, int height, int bpp) { bool fullscreen = true; Config resolutionConfig; if (configInit(&resolutionConfig)) { if (configRead(&resolutionConfig, "f2_res.ini", false)) { int screenWidth; if (configGetInt(&resolutionConfig, "MAIN", "SCR_WIDTH", &screenWidth)) { width = screenWidth; } int screenHeight; if (configGetInt(&resolutionConfig, "MAIN", "SCR_HEIGHT", &screenHeight)) { height = screenHeight; } bool windowed; if (configGetBool(&resolutionConfig, "MAIN", "WINDOWED", &windowed)) { fullscreen = !windowed; } configGetBool(&resolutionConfig, "IFACE", "IFACE_BAR_MODE", &gInterfaceBarMode); configGetInt(&resolutionConfig, "IFACE", "IFACE_BAR_WIDTH", &gInterfaceBarWidth); configGetInt(&resolutionConfig, "IFACE", "IFACE_BAR_SIDE_ART", &gInterfaceSidePanelsImageId); configGetBool(&resolutionConfig, "IFACE", "IFACE_BAR_SIDES_ORI", &gInterfaceSidePanelsExtendFromScreenEdge); } configFree(&resolutionConfig); } if (_GNW95_init_window(width, height, fullscreen) == -1) { return -1; } if (directDrawInit(width, height, bpp) == -1) { return -1; } _scr_size.left = 0; _scr_size.top = 0; _scr_size.right = width - 1; _scr_size.bottom = height - 1; _mouse_blit_trans = NULL; _scr_blit = _GNW95_ShowRect; _zero_mem = _GNW95_zero_vid_mem; _mouse_blit = _GNW95_ShowRect; return 0; } // 0x4CAECC int _init_vesa_mode(int width, int height) { return _GNW95_init_mode_ex(width, height, 8); } // 0x4CAEDC int _GNW95_init_window(int width, int height, bool fullscreen) { if (gSdlWindow == NULL) { SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); if (SDL_Init(SDL_INIT_VIDEO) != 0) { return -1; } Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI; if (fullscreen) { windowFlags |= SDL_WINDOW_FULLSCREEN; } gSdlWindow = SDL_CreateWindow(gProgramWindowTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, windowFlags); if (gSdlWindow == NULL) { return -1; } if (!createRenderer(width, height)) { destroyRenderer(); SDL_DestroyWindow(gSdlWindow); gSdlWindow = NULL; return -1; } } return 0; } // 0x4CAF9C int directDrawInit(int width, int height, int bpp) { if (gSdlSurface != NULL) { unsigned char* palette = directDrawGetPalette(); directDrawFree(); if (directDrawInit(width, height, bpp) == -1) { return -1; } directDrawSetPalette(palette); return 0; } gSdlSurface = SDL_CreateRGBSurface(0, width, height, bpp, 0, 0, 0, 0); SDL_Color colors[256]; for (int index = 0; index < 256; index++) { colors[index].r = index; colors[index].g = index; colors[index].b = index; colors[index].a = 255; } SDL_SetPaletteColors(gSdlSurface->format->palette, colors, 0, 256); return 0; } // 0x4CB1B0 void directDrawFree() { if (gSdlSurface != NULL) { SDL_FreeSurface(gSdlSurface); gSdlSurface = NULL; } } // 0x4CB310 void directDrawSetPaletteInRange(unsigned char* palette, int start, int count) { if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) { SDL_Color colors[256]; if (count != 0) { for (int index = 0; index < count; index++) { colors[index].r = palette[index * 3] << 2; colors[index].g = palette[index * 3 + 1] << 2; colors[index].b = palette[index * 3 + 2] << 2; colors[index].a = 255; } } SDL_SetPaletteColors(gSdlSurface->format->palette, colors, start, count); SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL); } } // 0x4CB568 void directDrawSetPalette(unsigned char* palette) { if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) { SDL_Color colors[256]; for (int index = 0; index < 256; index++) { colors[index].r = palette[index * 3] << 2; colors[index].g = palette[index * 3 + 1] << 2; colors[index].b = palette[index * 3 + 2] << 2; colors[index].a = 255; } SDL_SetPaletteColors(gSdlSurface->format->palette, colors, 0, 256); SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL); } } // 0x4CB68C unsigned char* directDrawGetPalette() { // 0x6ACA24 static unsigned char palette[768]; if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) { SDL_Color* colors = gSdlSurface->format->palette->colors; for (int index = 0; index < 256; index++) { SDL_Color* color = &(colors[index]); palette[index * 3] = color->r >> 2; palette[index * 3 + 1] = color->g >> 2; palette[index * 3 + 2] = color->b >> 2; } } return palette; } // 0x4CB850 void _GNW95_ShowRect(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY) { blitBufferToBuffer(src + srcPitch * srcY + srcX, srcWidth, srcHeight, srcPitch, (unsigned char*)gSdlSurface->pixels + gSdlSurface->pitch * destY + destX, gSdlSurface->pitch); SDL_Rect srcRect; srcRect.x = destX; srcRect.y = destY; srcRect.w = srcWidth; srcRect.h = srcHeight; SDL_Rect destRect; destRect.x = destX; destRect.y = destY; SDL_BlitSurface(gSdlSurface, &srcRect, gSdlTextureSurface, &destRect); } // Clears drawing surface. // // 0x4CBBC8 void _GNW95_zero_vid_mem() { if (!gProgramIsActive) { return; } unsigned char* surface = (unsigned char*)gSdlSurface->pixels; for (int y = 0; y < gSdlSurface->h; y++) { memset(surface, 0, gSdlSurface->w); surface += gSdlSurface->pitch; } SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL); } int screenGetWidth() { // TODO: Make it on par with _xres; return rectGetWidth(&_scr_size); } int screenGetHeight() { // TODO: Make it on par with _yres. return rectGetHeight(&_scr_size); } int screenGetVisibleHeight() { int windowBottomMargin = 0; if (!gInterfaceBarMode) { windowBottomMargin = INTERFACE_BAR_HEIGHT; } return screenGetHeight() - windowBottomMargin; } static bool createRenderer(int width, int height) { gSdlRenderer = SDL_CreateRenderer(gSdlWindow, -1, 0); if (gSdlRenderer == NULL) { return false; } if (SDL_RenderSetLogicalSize(gSdlRenderer, width, height) != 0) { return false; } gSdlTexture = SDL_CreateTexture(gSdlRenderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, width, height); if (gSdlTexture == NULL) { return false; } Uint32 format; if (SDL_QueryTexture(gSdlTexture, &format, NULL, NULL, NULL) != 0) { return false; } gSdlTextureSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, SDL_BITSPERPIXEL(format), format); if (gSdlTextureSurface == NULL) { return false; } return true; } static void destroyRenderer() { if (gSdlTextureSurface != NULL) { SDL_FreeSurface(gSdlTextureSurface); gSdlTextureSurface = NULL; } if (gSdlTexture != NULL) { SDL_DestroyTexture(gSdlTexture); gSdlTexture = NULL; } if (gSdlRenderer != NULL) { SDL_DestroyRenderer(gSdlRenderer); gSdlRenderer = NULL; } } void handleWindowSizeChanged() { destroyRenderer(); createRenderer(screenGetWidth(), screenGetHeight()); } void renderPresent() { SDL_UpdateTexture(gSdlTexture, NULL, gSdlTextureSurface->pixels, gSdlTextureSurface->pitch); SDL_RenderClear(gSdlRenderer); SDL_RenderCopy(gSdlRenderer, gSdlTexture, NULL, NULL); SDL_RenderPresent(gSdlRenderer); } } // namespace fallout