From 1379514eff9d83838395f1811316e23aded55fea Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Sat, 30 Dec 2023 18:48:02 +0800 Subject: [PATCH] 1 --- Plugins/Renderer/gl_draw.cpp | 510 +++++++++++++++++++++++++++++---- Plugins/Renderer/gl_draw.h | 4 +- Plugins/Renderer/gl_local.h | 7 +- Plugins/Renderer/gl_rmain.cpp | 252 ++++++++++++++-- Plugins/Renderer/gl_studio.cpp | 4 +- Plugins/Renderer/gl_water.cpp | 2 +- Plugins/Renderer/gl_wsurf.cpp | 16 +- Plugins/Renderer/gl_wsurf.h | 4 +- 8 files changed, 699 insertions(+), 100 deletions(-) diff --git a/Plugins/Renderer/gl_draw.cpp b/Plugins/Renderer/gl_draw.cpp index db626b59..533a1bb1 100644 --- a/Plugins/Renderer/gl_draw.cpp +++ b/Plugins/Renderer/gl_draw.cpp @@ -427,7 +427,7 @@ void GL_UnloadTextureByTextureId(int gltexturenum, bool notify_callback) } } -void GL_UploadDXT(gl_loadtexture_state_t *state) +void GL_UploadCompressedTexture(gl_loadtexture_state_t *state) { int iTextureTarget = GL_TEXTURE_2D; int iMipmapTextureTarget = GL_TEXTURE_2D; @@ -470,7 +470,7 @@ void GL_UploadDXT(gl_loadtexture_state_t *state) for (size_t i = 0; i < state->mipmaps.size(); ++i) { - glCompressedTexImage2D(iMipmapTextureTarget, state->mipmaps[i].level, state->format, state->mipmaps[i].width, state->mipmaps[i].height, 0, state->mipmaps[i].size, state->mipmaps[i].data); + glCompressedTexImage2D(iMipmapTextureTarget, state->mipmaps[i].level, state->internalformat, state->mipmaps[i].width, state->mipmaps[i].height, 0, state->mipmaps[i].size, state->mipmaps[i].data); if (!state->mipmap) break; @@ -483,7 +483,7 @@ void GL_UploadDXT(gl_loadtexture_state_t *state) } } -void GL_UploadRGBA8(gl_loadtexture_state_t* state) +void GL_UploadUncompressedTexture(gl_loadtexture_state_t* state) { int iTextureTarget = GL_TEXTURE_2D; int iMipmapTextureTarget = GL_TEXTURE_2D; @@ -526,8 +526,26 @@ void GL_UploadRGBA8(gl_loadtexture_state_t* state) for (size_t i = 0; i < state->mipmaps.size(); ++i) { - glTexImage2D(iMipmapTextureTarget, state->mipmaps[i].level, state->format, state->mipmaps[i].width, state->mipmaps[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, state->mipmaps[i].data); - + if (state->internalformat == GL_RGBA8) + { + glTexImage2D(iMipmapTextureTarget, state->mipmaps[i].level, state->internalformat, state->mipmaps[i].width, state->mipmaps[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, state->mipmaps[i].data); + } + else if (state->internalformat == GL_RGB8) + { + glTexImage2D(iMipmapTextureTarget, state->mipmaps[i].level, state->internalformat, state->mipmaps[i].width, state->mipmaps[i].height, 0, GL_RGB, GL_UNSIGNED_BYTE, state->mipmaps[i].data); + } + else if (state->internalformat == GL_RGBA32F) + { + glTexImage2D(iMipmapTextureTarget, state->mipmaps[i].level, state->internalformat, state->mipmaps[i].width, state->mipmaps[i].height, 0, GL_RGBA, GL_FLOAT, state->mipmaps[i].data); + } + else if (state->internalformat == GL_RGB32F) + { + glTexImage2D(iMipmapTextureTarget, state->mipmaps[i].level, state->internalformat, state->mipmaps[i].width, state->mipmaps[i].height, 0, GL_RGB, GL_FLOAT, state->mipmaps[i].data); + } + else + { + g_pMetaHookAPI->SysError("GL_UploadUncompressedTexture: bogus internalformat 0x%X.", state->internalformat); + } if (!state->mipmap) break; } @@ -1190,11 +1208,11 @@ int GL_LoadTexture3(gltexture_t* glt, GL_TEXTURETYPE textureType, gl_loadtexture if (state->compressed) { - GL_UploadDXT(state); + GL_UploadCompressedTexture(state); } else { - GL_UploadRGBA8(state); + GL_UploadUncompressedTexture(state); } glBindTexture(iTextureTarget, 0); @@ -1238,7 +1256,7 @@ int GL_LoadTexture2(char* identifier, GL_TEXTURETYPE textureType, int width, int gl_loadtexture_state_t state; - state.format = GL_RGBA8; + state.internalformat = GL_RGBA8; state.compressed = false; state.width = width; state.height = height; @@ -1498,7 +1516,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_RGBA_BPTC_UNORM; + state->internalformat = GL_COMPRESSED_RGBA_BPTC_UNORM; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1524,7 +1542,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; + state->internalformat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1550,7 +1568,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + state->internalformat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1576,7 +1594,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + state->internalformat = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1602,7 +1620,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + state->internalformat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1628,7 +1646,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + state->internalformat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1654,7 +1672,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + state->internalformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1680,7 +1698,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + state->internalformat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1714,7 +1732,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_RGBA_BPTC_UNORM; + state->internalformat = GL_COMPRESSED_RGBA_BPTC_UNORM; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1742,7 +1760,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + state->internalformat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1770,7 +1788,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + state->internalformat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1797,7 +1815,7 @@ bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize return false; } - state->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + state->internalformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; state->compressed = true; state->mipmaps.emplace_back(i, buf + offset, size, w, h); @@ -1866,6 +1884,79 @@ const char * V_GetFileExtension( const char * path ) return src; } +class CScopedFIBitmap { +public: + CScopedFIBitmap(FIBITMAP* bitmap) : m_bitmap(bitmap) {} + + ~CScopedFIBitmap() { + if (m_bitmap) { + FreeImage_Unload(m_bitmap); + m_bitmap = nullptr; + } + } + + // Delete copy constructor and copy assignment operator + CScopedFIBitmap(const CScopedFIBitmap&) = delete; + CScopedFIBitmap& operator=(const CScopedFIBitmap&) = delete; + + // Optionally add move constructor and move assignment operator + CScopedFIBitmap(CScopedFIBitmap&& other) noexcept : m_bitmap(other.m_bitmap) { + other.m_bitmap = nullptr; + } + CScopedFIBitmap& operator=(CScopedFIBitmap&& other) noexcept { + if (this != &other) { + if (m_bitmap) { + FreeImage_Unload(m_bitmap); + } + m_bitmap = other.m_bitmap; + other.m_bitmap = nullptr; + } + return *this; + } + + // Access the FIBITMAP* + FIBITMAP* get() const { return m_bitmap; } + +private: + FIBITMAP* m_bitmap; +}; + +class CScopedFileHandle { +public: + CScopedFileHandle(FileHandle_t filehandle) : m_filehandle(filehandle) {} + + ~CScopedFileHandle() { + if (m_filehandle) { + FILESYSTEM_ANY_CLOSE(m_filehandle); + m_filehandle = nullptr; + } + } + + // Delete copy constructor and copy assignment operator + CScopedFileHandle(const CScopedFileHandle&) = delete; + CScopedFileHandle& operator=(const CScopedFileHandle&) = delete; + + // Optionally add move constructor and move assignment operator + CScopedFileHandle(CScopedFileHandle&& other) noexcept : m_filehandle(other.m_filehandle) { + other.m_filehandle = nullptr; + } + CScopedFileHandle& operator=(CScopedFileHandle&& other) noexcept { + if (this != &other) { + if (m_filehandle) { + FILESYSTEM_ANY_CLOSE(m_filehandle); + } + m_filehandle = other.m_filehandle; + other.m_filehandle = nullptr; + } + return *this; + } + + FileHandle_t get() const { return m_filehandle; } + +private: + FileHandle_t m_filehandle; +}; + unsigned WINAPI FI_Read(void *buffer, unsigned size, unsigned count, fi_handle handle) { if(FILESYSTEM_ANY_READ(buffer, size*count, handle)) @@ -1891,74 +1982,166 @@ long WINAPI FI_Tell(fi_handle handle) return FILESYSTEM_ANY_TELL(handle); } -bool LoadImageGeneric(const char *filename, const char* pathId, byte *buf, size_t bufSize, gl_loadtexture_state_t *state, bool throw_warning_on_missing) +bool LoadImageGenericRGBA32F(const char* filename, byte* buf, size_t bufSize, FIBITMAP* fiB, gl_loadtexture_state_t* state) { - FileHandle_t fileHandle = FILESYSTEM_ANY_OPEN(filename, "rb", pathId); + size_t pos = 0; + size_t w = FreeImage_GetWidth(fiB); + size_t h = FreeImage_GetHeight(fiB); + size_t imageSize = w * h * sizeof(vec4_t); - if (!fileHandle) + if (imageSize > bufSize) { - if (throw_warning_on_missing) - { - gEngfuncs.Con_Printf("LoadImageGeneric: Could not open %s.\n", filename); - } + gEngfuncs.Con_Printf("LoadImageGenericRGB32F: Could not load %s, texture too large.\n", filename); return false; } - FreeImageIO fiIO; - fiIO.read_proc = FI_Read; - fiIO.write_proc = FI_Write; - fiIO.seek_proc = FI_Seek; - fiIO.tell_proc = FI_Tell; + byte* imageData = FreeImage_GetBits(fiB); - FREE_IMAGE_FORMAT fiFormat = FreeImage_GetFileTypeFromHandle(&fiIO, (fi_handle)fileHandle); + size_t rowSize = w * sizeof(vec4_t); - if(fiFormat == FIF_UNKNOWN) - fiFormat = FreeImage_GetFIFFromFilename(filename); + // Flip the image vertically into the destination buffer + for (unsigned int y = 0; y < h; ++y) { + // Calculate the starting position of the source row + byte* sourceRow = imageData + y * rowSize; + // Calculate the starting position of the destination row + // We start from the end of the buffer and move backwards + byte* destRow = buf + (h - y - 1) * rowSize; - if(fiFormat == FIF_UNKNOWN) - { - gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, Unsupported format.\n", filename); - FILESYSTEM_ANY_CLOSE(fileHandle); - return false; - } + // Copy the source row to the destination row + memcpy(destRow, sourceRow, rowSize); + } - if(!FreeImage_FIFSupportsReading(fiFormat)) - { - gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, Unsupported format.\n", filename); - FILESYSTEM_ANY_CLOSE(fileHandle); + float r_texgamma = 1.0f / v_texgamma->value; + + for (unsigned int y = 0; y < h; ++y) { + for (unsigned int x = 0; x < w; ++x) { + float* row = (float*)(buf + y * rowSize + x * sizeof(vec4_t)); + + row[0] = pow(row[0], r_texgamma); + row[1] = pow(row[1], r_texgamma); + row[2] = pow(row[2], r_texgamma); + } + } + + state->internalformat = GL_RGBA32F; + state->compressed = false; + state->width = w; + state->height = h; + state->mipmaps.emplace_back(0, buf, pos, w, h); + + return true; +} + +bool LoadImageGenericRGB32F(const char* filename, byte* buf, size_t bufSize, FIBITMAP* fiB, gl_loadtexture_state_t* state) +{ + size_t pos = 0; + size_t w = FreeImage_GetWidth(fiB); + size_t h = FreeImage_GetHeight(fiB); + size_t imageSize = w * h * sizeof(vec3_t); + + if (imageSize > bufSize) + { + gEngfuncs.Con_Printf("LoadImageGenericRGB32F: Could not load %s, texture too large.\n", filename); return false; - } + } - FIBITMAP *fiB = FreeImage_LoadFromHandle(fiFormat, &fiIO, (fi_handle)fileHandle); + byte* imageData = FreeImage_GetBits(fiB); - FILESYSTEM_ANY_CLOSE(fileHandle); + size_t rowSize = w * sizeof(vec3_t); - if (!fiB) + // Flip the image vertically into the destination buffer + for (unsigned int y = 0; y < h; ++y) { + // Calculate the starting position of the source row + byte* sourceRow = imageData + y * rowSize; + // Calculate the starting position of the destination row + // We start from the end of the buffer and move backwards + byte* destRow = buf + (h - y - 1) * rowSize; + + // Copy the source row to the destination row + memcpy(destRow, sourceRow, rowSize); + } + + float r_texgamma = 1.0f / v_gamma->value; + + for (unsigned int y = 0; y < h; ++y) { + for (unsigned int x = 0; x < w; ++x) { + float* row = (float*)(buf + y * rowSize + x * sizeof(vec3_t)); + + row[0] = pow(row[0], r_texgamma); + row[1] = pow(row[1], r_texgamma); + row[2] = pow(row[2], r_texgamma); + } + } + + state->internalformat = GL_RGB32F; + state->compressed = false; + state->width = w; + state->height = h; + state->mipmaps.emplace_back(0, buf, pos, w, h); + + return true; +} + +bool LoadImageGenericRGBA8(const char *filename, byte* buf, size_t bufSize, FIBITMAP* fiB, gl_loadtexture_state_t* state) +{ + size_t pos = 0; + size_t w = FreeImage_GetWidth(fiB); + size_t h = FreeImage_GetHeight(fiB); + size_t blockSize = FreeImage_GetLine(fiB) / w; + + if (w * h * 4 > bufSize) { - gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, FreeImage_LoadFromHandle failed.\n", filename); + gEngfuncs.Con_Printf("LoadImageGenericRGBA8: Could not load %s, texture too large.\n", filename); return false; } + for (size_t y = 0; y < h; ++y) + { + BYTE* bits = FreeImage_GetScanLine(fiB, h - y - 1); + for (size_t x = 0; x < w; ++x) + { + buf[pos++] = bits[FI_RGBA_RED];//B + buf[pos++] = bits[FI_RGBA_GREEN];//G + buf[pos++] = bits[FI_RGBA_BLUE];//R + if (blockSize == 4) + buf[pos++] = bits[FI_RGBA_ALPHA];//Alpha + else + buf[pos++] = 255; + bits += blockSize; + } + } + + state->internalformat = GL_RGBA8; + state->compressed = false; + state->width = w; + state->height = h; + state->mipmaps.emplace_back(0, buf, pos, w, h); + + return true; +} + +bool LoadImageGenericRGB8(const char* filename, byte* buf, size_t bufSize, FIBITMAP* fiB, gl_loadtexture_state_t* state) +{ size_t pos = 0; size_t w = FreeImage_GetWidth(fiB); size_t h = FreeImage_GetHeight(fiB); size_t blockSize = FreeImage_GetLine(fiB) / w; - if(w * h * 4 > bufSize) + if (w * h * 4 > bufSize) { - FreeImage_Unload(fiB); + gEngfuncs.Con_Printf("LoadImageGenericRGB8: Could not load %s, texture too large.\n", filename); return false; } - for(size_t y = 0; y < h; ++y ) + for (size_t y = 0; y < h; ++y) { - BYTE *bits = FreeImage_GetScanLine(fiB, h-y-1); - for( size_t x = 0; x < w; ++x ) + BYTE* bits = FreeImage_GetScanLine(fiB, h - y - 1); + for (size_t x = 0; x < w; ++x) { buf[pos++] = bits[FI_RGBA_RED];//B buf[pos++] = bits[FI_RGBA_GREEN];//G buf[pos++] = bits[FI_RGBA_BLUE];//R - if(blockSize == 4) + if (blockSize == 4) buf[pos++] = bits[FI_RGBA_ALPHA];//Alpha else buf[pos++] = 255; @@ -1966,13 +2149,210 @@ bool LoadImageGeneric(const char *filename, const char* pathId, byte *buf, size_ } } - state->format = GL_RGBA8; + state->internalformat = GL_RGB8; state->compressed = false; state->width = w; state->height = h; state->mipmaps.emplace_back(0, buf, pos, w, h); - FreeImage_Unload(fiB); + return true; +} + +bool LoadImagePaletteRGBA8(const char* filename, byte* buf, size_t bufSize, FIBITMAP* fiB, gl_loadtexture_state_t* state) +{ + size_t pos = 0; + size_t w = FreeImage_GetWidth(fiB); + size_t h = FreeImage_GetHeight(fiB); + size_t blockSize = FreeImage_GetLine(fiB) / w; + + // Get the palette + RGBQUAD* palette = FreeImage_GetPalette(fiB); + + if (w * h * 4 > bufSize) + { + gEngfuncs.Con_Printf("LoadImagePaletteRGBA8: Could not load %s, texture too large.\n", filename); + return false; + } + + for (size_t y = 0; y < h; ++y) + { + BYTE* bits = FreeImage_GetScanLine(fiB, h - y - 1); + for (size_t x = 0; x < w; ++x) + { + const RGBQUAD& color = palette[bits[x]]; + + buf[pos++] = color.rgbRed;//R + buf[pos++] = color.rgbGreen;//G + buf[pos++] = color.rgbBlue;//B + buf[pos++] = 255; + } + } + + state->internalformat = GL_RGBA8; + state->compressed = false; + state->width = w; + state->height = h; + state->mipmaps.emplace_back(0, buf, pos, w, h); + + return true; +} + +bool LoadImagePaletteRGB8(const char* filename, byte* buf, size_t bufSize, FIBITMAP* fiB, gl_loadtexture_state_t* state) +{ + size_t pos = 0; + size_t w = FreeImage_GetWidth(fiB); + size_t h = FreeImage_GetHeight(fiB); + size_t blockSize = FreeImage_GetLine(fiB) / w; + + // Get the palette + RGBQUAD* palette = FreeImage_GetPalette(fiB); + + if (w * h * 4 > bufSize) + { + gEngfuncs.Con_Printf("LoadImagePaletteRGB8: Could not load %s, texture too large.\n", filename); + return false; + } + + for (size_t y = 0; y < h; ++y) + { + BYTE* bits = FreeImage_GetScanLine(fiB, h - y - 1); + for (size_t x = 0; x < w; ++x) + { + const RGBQUAD& color = palette[bits[x]]; + + buf[pos++] = color.rgbRed;//R + buf[pos++] = color.rgbGreen;//G + buf[pos++] = color.rgbBlue;//B + buf[pos++] = 255; + } + } + + state->internalformat = GL_RGB8; + state->compressed = false; + state->width = w; + state->height = h; + state->mipmaps.emplace_back(0, buf, pos, w, h); + + return true; +} + +bool LoadImageGeneric(const char *filename, const char* pathId, byte *buf, size_t bufSize, gl_loadtexture_state_t *state, bool throw_warning_on_missing) +{ + FileHandle_t fileHandle = FILESYSTEM_ANY_OPEN(filename, "rb", pathId); + + if (!fileHandle) + { + if (throw_warning_on_missing) + { + gEngfuncs.Con_Printf("LoadImageGeneric: Could not open %s.\n", filename); + } + return false; + } + + CScopedFileHandle scopedFileHandle(fileHandle); + + FreeImageIO fiIO; + fiIO.read_proc = FI_Read; + fiIO.write_proc = FI_Write; + fiIO.seek_proc = FI_Seek; + fiIO.tell_proc = FI_Tell; + + FREE_IMAGE_FORMAT fiFormat = FreeImage_GetFileTypeFromHandle(&fiIO, (fi_handle)fileHandle); + + if (fiFormat == FIF_UNKNOWN) + { + fiFormat = FreeImage_GetFIFFromFilename(filename); + } + + if(fiFormat == FIF_UNKNOWN) + { + gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, Unknown format.\n", filename); + return false; + } + + if(!FreeImage_FIFSupportsReading(fiFormat)) + { + gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, Unsupported format.\n", filename); + return false; + } + + FIBITMAP* fiB = FreeImage_LoadFromHandle(fiFormat, &fiIO, (fi_handle)fileHandle); + + if (!fiB) + { + gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, FreeImage_LoadFromHandle failed.\n", filename); + return false; + } + + CScopedFIBitmap scopedBitmap(fiB); + + if (fiFormat == FIF_HDR) + { + FREE_IMAGE_COLOR_TYPE colorType = FreeImage_GetColorType(scopedBitmap.get()); + + if (colorType == FIC_RGBALPHA) + { + FIBITMAP* fiBFloat = FreeImage_ConvertToRGBAF(scopedBitmap.get()); + + if (!fiBFloat) + { + gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, FreeImage_ConvertToRGBAF failed.\n", filename); + return false; + } + + CScopedFIBitmap scopedBitmapFloat(fiBFloat); + + if (!LoadImageGenericRGBA32F(filename, buf, bufSize, scopedBitmapFloat.get(), state)) + return false; + + } + else if (colorType == FIC_RGB) + { + FIBITMAP* fiBFloat = FreeImage_ConvertToRGBF(scopedBitmap.get()); + + if (!fiBFloat) + { + gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, FreeImage_ConvertToRGBF failed.\n", filename); + return false; + } + + CScopedFIBitmap scopedBitmapFloat(fiBFloat); + + if (!LoadImageGenericRGB32F(filename, buf, bufSize, scopedBitmapFloat.get(), state)) + return false; + } + } + else + { + FREE_IMAGE_COLOR_TYPE colorType = FreeImage_GetColorType(scopedBitmap.get()); + + if (colorType == FIC_RGBALPHA) + { + if (!LoadImageGenericRGBA8(filename, buf, bufSize, scopedBitmap.get(), state)) + { + return false; + } + } + else if (colorType == FIC_RGB) + { + if (!LoadImageGenericRGBA8(filename, buf, bufSize, scopedBitmap.get(), state)) + { + return false; + } + } + else if (colorType == FIC_PALETTE) + { + if (!LoadImagePaletteRGBA8(filename, buf, bufSize, scopedBitmap.get(), state)) + { + return false; + } + } + else + { + gEngfuncs.Con_Printf("LoadImageGeneric: Could not load %s, bogus color type: %d.\n", filename, colorType); + return false; + } + } return true; } @@ -2039,14 +2419,14 @@ bool SaveImageGeneric(const char *filename, const char* pathId, int width, int h return true; } -int R_LoadRGBATextureFromMemory(const char* identifier, void* data, int width, int height, GL_TEXTURETYPE textureType, bool mipmap) +int R_LoadRGBA8TextureFromMemory(const char* identifier, void* data, int width, int height, GL_TEXTURETYPE textureType, bool mipmap) { gl_loadtexture_state_t state; + state.internalformat = GL_RGBA8; + state.compressed = false; state.width = width; state.height = height; - state.format = GL_RGBA8; - state.compressed = false; state.mipmap = mipmap; state.mipmaps.emplace_back(0, data, 0, width, height); @@ -2137,7 +2517,9 @@ void __fastcall enginesurface_drawSetTextureFile(void* pthis, int dummy, int tex gPrivateFuncs.enginesurface_drawSetTextureRGBA(pthis, dummy, textureId, (const char*)texloader_buffer, state.width, state.height, hardwareFilter, true); - GL_UploadDXT(&state); + + GL_UploadCompressedTexture(&state); + bLoaded = true; } if (!bLoaded && LoadDDS(filepath, NULL, texloader_buffer, sizeof(texloader_buffer), &state, false) && !state.cubemap) @@ -2145,7 +2527,9 @@ void __fastcall enginesurface_drawSetTextureFile(void* pthis, int dummy, int tex gPrivateFuncs.enginesurface_drawSetTextureRGBA(pthis, dummy, textureId, (const char *)texloader_buffer, state.width, state.height, hardwareFilter, true); - GL_UploadDXT(&state); + + GL_UploadCompressedTexture(&state); + bLoaded = true; } } diff --git a/Plugins/Renderer/gl_draw.h b/Plugins/Renderer/gl_draw.h index 97bfb28d..e3b0c46f 100644 --- a/Plugins/Renderer/gl_draw.h +++ b/Plugins/Renderer/gl_draw.h @@ -55,7 +55,7 @@ typedef struct gl_loadtexture_state_s filter = 0; mipmap = false; - format = 0; + internalformat = 0; compressed = false; } @@ -69,7 +69,7 @@ typedef struct gl_loadtexture_state_s bool mipmap; //Loader field - GLuint format; + GLuint internalformat; bool compressed; std::vector mipmaps; diff --git a/Plugins/Renderer/gl_local.h b/Plugins/Renderer/gl_local.h index 0484ca2e..6eaabc91 100644 --- a/Plugins/Renderer/gl_local.h +++ b/Plugins/Renderer/gl_local.h @@ -355,7 +355,10 @@ entity_state_t *R_GetPlayerState(int index); bool CL_IsDevOverviewMode(void); int CL_FxBlend(cl_entity_t *entity); void R_DrawCurrentEntity(bool bTransparent); +void R_DrawEntitiesOnList(void); void R_DrawTEntitiesOnList(int onlyClientDraw); +void R_DrawEntitiesForViewModel(void); +void R_DrawTEntitiesForViewModel(void); void R_AddTEntity(cl_entity_t *pEnt); void GL_Shutdown(void); void GL_Init(void); @@ -441,7 +444,7 @@ void GL_FrameBufferColorTextureOITBlend(FBO_Container_t *s); int GL_LoadTextureEx(const char* identifier, GL_TEXTURETYPE textureType, gl_loadtexture_state_t* state); int R_LoadTextureFromFile(const char *filename, const char * identifier, int *width, int *height, GL_TEXTURETYPE type, bool mipmap, bool throw_warning_on_missing); -int R_LoadRGBATextureFromMemory(const char* identifier, void* data, int width, int height, GL_TEXTURETYPE type, bool mipmap); +int R_LoadRGBA8TextureFromMemory(const char* identifier, void* data, int width, int height, GL_TEXTURETYPE type, bool mipmap); bool LoadDDS(const char* filename, const char* pathId, byte* buf, size_t bufsize, gl_loadtexture_state_t* state, bool throw_warning_on_missing); bool LoadImageGeneric(const char* filename, const char* pathId, byte* buf, size_t bufSize, gl_loadtexture_state_t* state, bool throw_warning_on_missing); @@ -524,6 +527,8 @@ extern GLint r_viewport[4]; extern float r_entity_matrix[4][4]; extern float r_entity_color[4]; +extern bool r_draw_predrawviewmodel; +extern bool r_draw_drawviewmodel; extern bool r_draw_analyzingstudio; extern bool r_draw_deferredtrans; extern bool r_draw_hasalpha; diff --git a/Plugins/Renderer/gl_rmain.cpp b/Plugins/Renderer/gl_rmain.cpp index 239101b6..6a95dbb2 100644 --- a/Plugins/Renderer/gl_rmain.cpp +++ b/Plugins/Renderer/gl_rmain.cpp @@ -4,6 +4,8 @@ #include #include +//#define HAS_VIEWMODEL_PASS + private_funcs_t gPrivateFuncs = { 0 }; refdef_t r_refdef = { 0 }; @@ -138,8 +140,19 @@ bool g_bPortalClipPlaneEnabled[6] = { false }; vec4_t g_PortalClipPlane[6] = {0}; -float r_entity_matrix[4][4]; -float r_entity_color[4]; +float r_entity_matrix[4][4] = { 0 }; +float r_entity_color[4] = {0}; + +#if defined(HAS_VIEWMODEL_PASS) +std::vector g_ViewModelPassOpaqueEntity; +std::vector g_ViewModelPassTransEntity; +#endif + +//This is the pass that collects tempents created by ViewModel's StudioEvents +bool r_draw_predrawviewmodel = false; + +//This is the pass that actually draw ViewModel and it's muzzleflash +bool r_draw_drawviewmodel = false; //This is the very first pass for studiomodel mesh analysis bool r_draw_analyzingstudio = false; @@ -1209,8 +1222,15 @@ void R_DrawViewModel(void) return; } + r_draw_drawviewmodel = true; + glDepthRange(0, 0.3); +#if 0 + int original_numVisEdicts = (*cl_numvisedicts); + int original_numTransObjects = (*numTransObjs); +#endif + switch ((*currententity)->model->type) { case mod_studio: @@ -1252,8 +1272,18 @@ void R_DrawViewModel(void) } } +#if 0 + + R_DrawEntitiesForViewModel(); + R_DrawTEntitiesForViewModel(); +#endif + glDepthRange(0, 1); + + //Valve add this shit for what? idk glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + r_draw_drawviewmodel = false; } void R_PolyBlend(void) @@ -1679,6 +1709,15 @@ void R_RenderPreFrame() { R_EntityComponents_PreFrame(); } + +void R_RenderStartView() +{ +#if defined(HAS_VIEWMODEL_PASS) + g_ViewModelPassOpaqueEntity.clear(); + g_ViewModelPassTransEntity.clear(); +#endif +} + /* Called only once per frame, before running any render pass */ @@ -1774,6 +1813,8 @@ void R_PreRenderView() } } + R_RenderStartView(); + R_RenderShadowMap(); R_RenderWaterPass(); @@ -1837,6 +1878,14 @@ void R_PreDrawViewModel(void) if ((*cl_viewentity) > r_params.maxclients) return; + r_draw_predrawviewmodel = true; + +#if defined(HAS_VIEWMODEL_PASS) + + int original_numVisEdicts = (*cl_numvisedicts); + int original_numTransObjects = (*numTransObjs); +#endif + switch ((*currententity)->model->type) { case mod_studio: @@ -1863,6 +1912,24 @@ void R_PreDrawViewModel(void) break; } } + +#if defined(HAS_VIEWMODEL_PASS) + for (int i = original_numVisEdicts; i < (*cl_numvisedicts); ++i) + { + g_ViewModelPassOpaqueEntity.emplace_back(cl_visedicts[i]); + } + + for (int i = original_numTransObjects; i < (*numTransObjs); ++i) + { + g_ViewModelPassTransEntity.emplace_back((*transObjects)[i]); + } + + (*cl_numvisedicts) = original_numVisEdicts; + (*numTransObjs) = original_numTransObjects; + +#endif + + r_draw_predrawviewmodel = false; } bool R_IsRenderingPortal(void) @@ -1926,12 +1993,16 @@ void R_RenderView_SvEngine(int viewIdx) glDepthRange(0, 1); if (!(*r_refdef.onlyClientDraws)) + { + //Allocate TEMPENT here R_PreDrawViewModel(); + } R_RenderScene(); if (!(*r_refdef.onlyClientDraws)) { + //ViewModel and Muzzleflash here R_SetupGLForViewModel(); R_DrawViewModel(); } @@ -2711,6 +2782,46 @@ void R_AdjustScopeFOVForViewModel(float *fov) } } +void R_UseProjMatrixForViewModel(void) +{ + scene_ubo_t SceneUBO; + memcpy(SceneUBO.projMatrix, r_viewmodel_projection_matrix, sizeof(mat4)); + memcpy(SceneUBO.invProjMatrix, r_viewmodel_projection_matrix_inv, sizeof(mat4)); + + if (glNamedBufferSubData) + { + glNamedBufferSubData(r_wsurf.hSceneUBO, offsetof(scene_ubo_t, projMatrix), sizeof(mat4), &SceneUBO.projMatrix); + glNamedBufferSubData(r_wsurf.hSceneUBO, offsetof(scene_ubo_t, invProjMatrix), sizeof(mat4), &SceneUBO.invProjMatrix); + } + else + { + glBindBuffer(GL_UNIFORM_BUFFER, r_wsurf.hSceneUBO); + glBufferSubData(GL_UNIFORM_BUFFER, offsetof(scene_ubo_t, projMatrix), sizeof(mat4), &SceneUBO.projMatrix); + glBufferSubData(GL_UNIFORM_BUFFER, offsetof(scene_ubo_t, invProjMatrix), sizeof(mat4), &SceneUBO.invProjMatrix); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } +} + +void R_UseProjMatrixForWorld(void) +{ + scene_ubo_t SceneUBO; + memcpy(SceneUBO.projMatrix, r_projection_matrix, sizeof(mat4)); + memcpy(SceneUBO.invProjMatrix, r_projection_matrix_inv, sizeof(mat4)); + + if (glNamedBufferSubData) + { + glNamedBufferSubData(r_wsurf.hSceneUBO, offsetof(scene_ubo_t, projMatrix), sizeof(mat4), &SceneUBO.projMatrix); + glNamedBufferSubData(r_wsurf.hSceneUBO, offsetof(scene_ubo_t, invProjMatrix), sizeof(mat4), &SceneUBO.invProjMatrix); + } + else + { + glBindBuffer(GL_UNIFORM_BUFFER, r_wsurf.hSceneUBO); + glBufferSubData(GL_UNIFORM_BUFFER, offsetof(scene_ubo_t, projMatrix), sizeof(mat4), &SceneUBO.projMatrix); + glBufferSubData(GL_UNIFORM_BUFFER, offsetof(scene_ubo_t, invProjMatrix), sizeof(mat4), &SceneUBO.invProjMatrix); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } +} + void R_SetupGLForViewModel(void) { if (!CL_IsDevOverviewMode() && viewmodel_fov->value > 0) @@ -2755,30 +2866,12 @@ void R_SetupGLForViewModel(void) R_SetupPerspective(r_xfov_viewmodel, r_yfov_viewmodel, 4.0f, (r_params.movevars ? r_params.movevars->zmax : 4096)); } - float viewmodel_projection_matrix[16]; - float viewmodel_projection_matrix_inv[16]; - - glGetFloatv(GL_PROJECTION_MATRIX, viewmodel_projection_matrix); + glGetFloatv(GL_PROJECTION_MATRIX, r_viewmodel_projection_matrix); glMatrixMode(GL_MODELVIEW); - InvertMatrix(viewmodel_projection_matrix, viewmodel_projection_matrix_inv); + InvertMatrix(r_viewmodel_projection_matrix, r_viewmodel_projection_matrix_inv); - scene_ubo_t SceneUBO; - memcpy(SceneUBO.projMatrix, viewmodel_projection_matrix, sizeof(mat4)); - memcpy(SceneUBO.invProjMatrix, viewmodel_projection_matrix_inv, sizeof(mat4)); - - if (glNamedBufferSubData) - { - glNamedBufferSubData(r_wsurf.hSceneUBO, offsetof(scene_ubo_t, projMatrix), sizeof(mat4), &SceneUBO.projMatrix); - glNamedBufferSubData(r_wsurf.hSceneUBO, offsetof(scene_ubo_t, invProjMatrix), sizeof(mat4), &SceneUBO.invProjMatrix); - } - else - { - glBindBuffer(GL_UNIFORM_BUFFER, r_wsurf.hSceneUBO); - glBufferSubData(GL_UNIFORM_BUFFER, offsetof(scene_ubo_t, projMatrix), sizeof(mat4), &SceneUBO.projMatrix); - glBufferSubData(GL_UNIFORM_BUFFER, offsetof(scene_ubo_t, invProjMatrix), sizeof(mat4), &SceneUBO.invProjMatrix); - glBindBuffer(GL_UNIFORM_BUFFER, 0); - } + R_UseProjMatrixForViewModel(); } } @@ -2956,7 +3049,7 @@ void R_SetupGL(void) InvertMatrix(gWorldToScreen, gScreenToWorld); InvertMatrix(r_world_matrix, r_world_matrix_inv); - InvertMatrix(r_projection_matrix, r_proj_matrix_inv); + InvertMatrix(r_projection_matrix, r_projection_matrix_inv); } void R_CheckVariables(void) @@ -3104,6 +3197,117 @@ void R_DrawEntitiesOnList(void) GL_EndProfile(&Profile_DrawEntitiesOnList); } +#if defined(HAS_VIEWMODEL_PASS) + +void R_AddTEntityForViewModel(cl_entity_t* ent) +{ + if (r_draw_shadowcaster) + return; + + if (!ent->model) + return; + + //Brush models with kRenderTransAlpha are forced to be opaque, except renderamt = 0 + if (ent->model->type == mod_brush && ent->curstate.rendermode == kRenderTransAlpha) + { + if (ent->curstate.renderamt == 0) + return; + + (*currententity) = ent; + + R_DrawCurrentEntity(false); + + return; + } + + transObjRef ref; + + float dist; + vec3_t v; + + if (!ent->model || ent->model->type != mod_brush || ent->curstate.rendermode != kRenderTransAlpha) + { + VectorAdd(ent->model->mins, ent->model->maxs, v); + VectorScale(v, 0.5f, v); + VectorAdd(v, ent->origin, v); + VectorSubtract(r_origin, v, v); + dist = DotProduct(v, v); + } + else + { + dist = 1000000000; + } + + ref.distance = dist; + ref.pEnt = ent; + + g_ViewModelPassTransEntity.emplace_back(ref); +} + +void R_DrawEntitiesForViewModel(void) +{ + if (!r_drawentities->value) + return; + + for (size_t i = 0; i < g_ViewModelPassOpaqueEntity.size(); ++i) + { + (*currententity) = g_ViewModelPassOpaqueEntity[i]; + + if ((*currententity)->curstate.rendermode != kRenderNormal) + { + R_AddTEntityForViewModel((*currententity)); + continue; + } + + if ((*currententity)->curstate.rendermode == kRenderNormal && + (*currententity)->model && + (*currententity)->model->type == mod_sprite && + gl_spriteblend->value) + { + R_AddTEntityForViewModel((*currententity)); + continue; + } + + if ((*currententity)->model && + (*currententity)->model->type != mod_sprite) + { + R_DrawCurrentEntity(false); + } + + //TODO: defer pass? + } +} + +void R_DrawTEntitiesForViewModel(void) +{ + if (!r_drawentities->value) + return; + + if (bUseOITBlend) + { + //TODO: oit stuffs... + } + else + { + std::qsort(g_ViewModelPassTransEntity.data(), g_ViewModelPassTransEntity.size(), sizeof(transObjRef), [](const void* a, const void* b) { + + const auto arg1 = (const transObjRef *)(a); + const auto arg2 = (const transObjRef *)(b); + + return (int)(arg1->distance > arg2->distance); + }); + + for (size_t i = 0; i < g_ViewModelPassTransEntity.size(); ++i) + { + (*currententity) = g_ViewModelPassTransEntity[i].pEnt; + + R_DrawCurrentEntity(true); + } + } +} + +#endif + void R_RenderFinalFog(void) { memcpy(r_fog_color, g_UserFogColor, sizeof(vec4_t)); diff --git a/Plugins/Renderer/gl_studio.cpp b/Plugins/Renderer/gl_studio.cpp index 6391ca3e..30eeac51 100644 --- a/Plugins/Renderer/gl_studio.cpp +++ b/Plugins/Renderer/gl_studio.cpp @@ -3022,11 +3022,11 @@ void R_StudioLoadExternalFile_Efx(bspentity_t* ent, studiohdr_t* studiohdr, stud #define REGISTER_EFX_FLAGS_KEY_VALUE(name) if (flags_string && !strcmp(flags_string, #name))\ {\ - studiohdr->flags |= EF_ROCKET; \ + studiohdr->flags |= name; \ }\ if (flags_string && !strcmp(flags_string, "-" #name))\ {\ - studiohdr->flags |= EF_ROCKET; \ + studiohdr->flags |= name; \ } REGISTER_EFX_FLAGS_KEY_VALUE(EF_ROCKET); diff --git a/Plugins/Renderer/gl_water.cpp b/Plugins/Renderer/gl_water.cpp index 6bfe53b3..ae920cbf 100644 --- a/Plugins/Renderer/gl_water.cpp +++ b/Plugins/Renderer/gl_water.cpp @@ -629,7 +629,7 @@ water_vbo_t *R_CreateWaterVBO(msurface_t *surf, int direction, wsurf_vbo_leaf_t char identifier[64] = { 0 }; snprintf(identifier, sizeof(identifier), "%s_ripple", surf->texinfo->texture->name); - WaterVBO->ripplemap = R_LoadRGBATextureFromMemory(identifier, WaterVBO->ripple_image, WaterVBO->ripple_width, WaterVBO->ripple_height, GLT_WORLD, true); + WaterVBO->ripplemap = R_LoadRGBA8TextureFromMemory(identifier, WaterVBO->ripple_image, WaterVBO->ripple_width, WaterVBO->ripple_height, GLT_WORLD, true); WaterVBO->ripple_spots[0] = (short *)malloc(imageSize * sizeof(short)); memset(WaterVBO->ripple_spots[0], 0, imageSize * sizeof(short)); diff --git a/Plugins/Renderer/gl_wsurf.cpp b/Plugins/Renderer/gl_wsurf.cpp index b660f917..525dfa04 100644 --- a/Plugins/Renderer/gl_wsurf.cpp +++ b/Plugins/Renderer/gl_wsurf.cpp @@ -13,11 +13,15 @@ cvar_t *r_wsurf_zprepass; int r_fog_mode = 0; float r_fog_control[3] = { 0 }; float r_fog_color[4] = { 0 }; -float r_shadow_matrix[3][16]; -float r_world_matrix_inv[16]; -float r_proj_matrix_inv[16]; -vec3_t r_frustum_origin[4]; -vec3_t r_frustum_vec[4]; +float r_shadow_matrix[3][16] = { 0 }; +float r_world_matrix_inv[16] = { 0 }; +float r_projection_matrix_inv[16] = { 0 }; + +float r_viewmodel_projection_matrix[16] = { 0 }; +float r_viewmodel_projection_matrix_inv[16] = { 0 }; + +vec3_t r_frustum_origin[4] = { 0 }; +vec3_t r_frustum_vec[4] = { 0 }; float r_znear = 0; float r_zfar = 0; bool r_ortho = false; @@ -4062,7 +4066,7 @@ void R_SetupSceneUBO(void) memcpy(SceneUBO.viewMatrix, r_world_matrix, sizeof(mat4)); memcpy(SceneUBO.projMatrix, r_projection_matrix, sizeof(mat4)); memcpy(SceneUBO.invViewMatrix, r_world_matrix_inv, sizeof(mat4)); - memcpy(SceneUBO.invProjMatrix, r_proj_matrix_inv, sizeof(mat4)); + memcpy(SceneUBO.invProjMatrix, r_projection_matrix_inv, sizeof(mat4)); memcpy(SceneUBO.shadowMatrix[0], r_shadow_matrix[0], sizeof(mat4)); memcpy(SceneUBO.shadowMatrix[1], r_shadow_matrix[1], sizeof(mat4)); memcpy(SceneUBO.shadowMatrix[2], r_shadow_matrix[2], sizeof(mat4)); diff --git a/Plugins/Renderer/gl_wsurf.h b/Plugins/Renderer/gl_wsurf.h index 96366aaa..2e5a09a4 100644 --- a/Plugins/Renderer/gl_wsurf.h +++ b/Plugins/Renderer/gl_wsurf.h @@ -405,7 +405,9 @@ extern float r_shadow_matrix[3][16]; extern vec3_t r_frustum_origin[4]; extern vec3_t r_frustum_vec[4]; extern float r_world_matrix_inv[16]; -extern float r_proj_matrix_inv[16]; +extern float r_projection_matrix_inv[16]; +extern float r_viewmodel_projection_matrix[16]; +extern float r_viewmodel_projection_matrix_inv[16]; extern float r_znear; extern float r_zfar; extern bool r_ortho;