Skip to content

Commit ef85b13

Browse files
psi29aBret Curtis
authored and
Bret Curtis
committed
Merge pull request #1740 from nikolaykasyanov/software-cursor-decompression
Decompress cursors using SDL software renderer on Mac or if OSG >= 3.5.8 or if OPENMW_DECOMPRESS_TEXTURES is set
1 parent 98063c5 commit ef85b13

File tree

5 files changed

+81
-35
lines changed

5 files changed

+81
-35
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
Bug #4412: openmw-iniimporter ignores data paths from config
8787
Bug #4413: Moving with 0 strength uses all of your fatigue
8888
Bug #4420: Camera flickering when I open up and close menus while sneaking
89+
Bug #4424: [macOS] Cursor is either empty or garbage when compiled against macOS 10.13 SDK
8990
Bug #4435: Item health is considered a signed integer
9091
Bug #4441: Adding items to currently disabled weapon-wielding creatures crashes the game
9192
Feature #1786: Round up encumbrance value in the encumbrance bar

apps/openmw/engine.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -428,9 +428,8 @@ void OMW::Engine::setWindowIcon()
428428
else
429429
{
430430
osg::ref_ptr<osg::Image> image = result.getImage();
431-
SDL_Surface* surface = SDLUtil::imageToSurface(image, true);
432-
SDL_SetWindowIcon(mWindow, surface);
433-
SDL_FreeSurface(surface);
431+
auto surface = SDLUtil::imageToSurface(image, true);
432+
SDL_SetWindowIcon(mWindow, surface.get());
434433
}
435434
}
436435

components/sdlutil/imagetosurface.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
namespace SDLUtil
77
{
88

9-
SDL_Surface* imageToSurface(osg::Image *image, bool flip)
9+
SurfaceUniquePtr imageToSurface(osg::Image *image, bool flip)
1010
{
1111
int width = image->s();
1212
int height = image->t();
@@ -22,7 +22,7 @@ SDL_Surface* imageToSurface(osg::Image *image, bool flip)
2222
static_cast<Uint8>(clr.g() * 255), static_cast<Uint8>(clr.b() * 255), static_cast<Uint8>(clr.a() * 255));
2323
}
2424

25-
return surface;
25+
return SurfaceUniquePtr(surface, SDL_FreeSurface);
2626
}
2727

2828
}

components/sdlutil/imagetosurface.hpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef OPENMW_COMPONENTS_SDLUTIL_IMAGETOSURFACE_H
22
#define OPENMW_COMPONENTS_SDLUTIL_IMAGETOSURFACE_H
33

4+
#include <memory>
5+
46
struct SDL_Surface;
57

68
namespace osg
@@ -10,10 +12,10 @@ namespace osg
1012

1113
namespace SDLUtil
1214
{
15+
typedef std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> SurfaceUniquePtr;
1316

1417
/// Convert an osg::Image to an SDL_Surface.
15-
/// @note The returned surface must be freed using SDL_FreeSurface.
16-
SDL_Surface* imageToSurface(osg::Image* image, bool flip=false);
18+
SurfaceUniquePtr imageToSurface(osg::Image* image, bool flip=false);
1719

1820
}
1921

components/sdlutil/sdlcursormanager.cpp

+72-28
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77

88
#include <SDL_mouse.h>
99
#include <SDL_endian.h>
10+
#include <SDL_render.h>
11+
#include <SDL_hints.h>
1012

1113
#include <osg/GraphicsContext>
1214
#include <osg/Geometry>
1315
#include <osg/Texture2D>
1416
#include <osg/TexMat>
17+
#include <osg/Version>
1518
#include <osgViewer/GraphicsWindow>
1619

1720
#include "imagetosurface.hpp"
@@ -22,8 +25,14 @@
2225
USE_GRAPHICSWINDOW()
2326
#endif
2427

25-
namespace
28+
namespace CursorDecompression
2629
{
30+
// macOS builds use the OSG fork that includes DXTC commit
31+
#if OSG_VERSION_GREATER_OR_EQUAL(3, 5, 8) || defined(__APPLE__)
32+
static const bool DXTCSupported = true;
33+
#else
34+
static const bool DXTCSupported = false;
35+
#endif
2736

2837
class MyGraphicsContext {
2938
public:
@@ -80,10 +89,8 @@ namespace
8089
osg::ref_ptr<osg::GraphicsContext> _gc;
8190
};
8291

83-
osg::ref_ptr<osg::Image> decompress (osg::ref_ptr<osg::Image> source, float rotDegrees)
92+
SDLUtil::SurfaceUniquePtr hardwareDecompress (osg::ref_ptr<osg::Image> source, float rotDegrees)
8493
{
85-
// TODO: use software decompression once S3TC patent expires
86-
8794
int width = source->s();
8895
int height = source->t();
8996

@@ -132,17 +139,6 @@ namespace
132139

133140
osg::ref_ptr<osg::Geometry> geom;
134141

135-
#if defined(__APPLE__)
136-
// Extra flip needed on OS X systems due to a driver bug
137-
const char* envval = getenv("OPENMW_CURSOR_WORKAROUND");
138-
bool workaround = !envval || envval == std::string("1");
139-
std::string vendorString = (const char*)glGetString(GL_VENDOR);
140-
if (!envval)
141-
workaround = vendorString.find("Intel") != std::string::npos || vendorString.find("ATI") != std::string::npos || vendorString.find("AMD") != std::string::npos;
142-
if (workaround)
143-
geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0));
144-
else
145-
#endif
146142
geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,-1,0), osg::Vec3(2,0,0), osg::Vec3(0,2,0));
147143

148144
geom->drawImplementation(renderInfo);
@@ -153,7 +149,52 @@ namespace
153149
source->releaseGLObjects();
154150
texture->releaseGLObjects();
155151

156-
return resultImage;
152+
return SDLUtil::imageToSurface(resultImage, true);
153+
}
154+
155+
SDLUtil::SurfaceUniquePtr softwareDecompress (osg::ref_ptr<osg::Image> source, float rotDegrees)
156+
{
157+
int width = source->s();
158+
int height = source->t();
159+
bool useAlpha = source->isImageTranslucent();
160+
161+
osg::ref_ptr<osg::Image> decompressedImage = new osg::Image;
162+
decompressedImage->setFileName(source->getFileName());
163+
decompressedImage->allocateImage(width, height, 1, useAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE);
164+
for (int s=0; s<width; ++s)
165+
for (int t=0; t<height; ++t)
166+
decompressedImage->setColor(source->getColor(s,t,0), s,t,0);
167+
168+
Uint32 redMask = 0x000000ff;
169+
Uint32 greenMask = 0x0000ff00;
170+
Uint32 blueMask = 0x00ff0000;
171+
Uint32 alphaMask = useAlpha ? 0xff000000 : 0;
172+
173+
SDL_Surface *cursorSurface = SDL_CreateRGBSurfaceFrom(decompressedImage->data(),
174+
width,
175+
height,
176+
decompressedImage->getPixelSizeInBits(),
177+
decompressedImage->getRowSizeInBytes(),
178+
redMask,
179+
greenMask,
180+
blueMask,
181+
alphaMask);
182+
183+
SDL_Surface *targetSurface = SDL_CreateRGBSurface(0, width, height, 32, redMask, greenMask, blueMask, alphaMask);
184+
SDL_Renderer *renderer = SDL_CreateSoftwareRenderer(targetSurface);
185+
186+
SDL_RenderClear(renderer);
187+
188+
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
189+
SDL_Texture *cursorTexture = SDL_CreateTextureFromSurface(renderer, cursorSurface);
190+
191+
SDL_RenderCopyEx(renderer, cursorTexture, NULL, NULL, -rotDegrees, NULL, SDL_FLIP_VERTICAL);
192+
193+
SDL_DestroyTexture(cursorTexture);
194+
SDL_FreeSurface(cursorSurface);
195+
SDL_DestroyRenderer(renderer);
196+
197+
return SDLUtil::SurfaceUniquePtr(targetSurface, SDL_FreeSurface);
157198
}
158199

159200
}
@@ -222,27 +263,30 @@ namespace SDLUtil
222263

223264
void SDLCursorManager::_createCursorFromResource(const std::string& name, int rotDegrees, osg::Image* image, Uint8 hotspot_x, Uint8 hotspot_y)
224265
{
225-
osg::ref_ptr<osg::Image> decompressed;
226-
227266
if (mCursorMap.find(name) != mCursorMap.end())
228267
return;
229268

269+
static bool forceSoftwareDecompression = (getenv("OPENMW_DECOMPRESS_TEXTURES") != 0);
270+
271+
SurfaceUniquePtr (*decompressionFunction)(osg::ref_ptr<osg::Image>, float);
272+
if (forceSoftwareDecompression || CursorDecompression::DXTCSupported) {
273+
decompressionFunction = CursorDecompression::softwareDecompress;
274+
} else {
275+
decompressionFunction = CursorDecompression::hardwareDecompress;
276+
}
277+
230278
try {
231-
decompressed = decompress(image, static_cast<float>(rotDegrees));
279+
auto surface = decompressionFunction(image, static_cast<float>(rotDegrees));
280+
281+
//set the cursor and store it for later
282+
SDL_Cursor* curs = SDL_CreateColorCursor(surface.get(), hotspot_x, hotspot_y);
283+
284+
mCursorMap.insert(CursorMap::value_type(std::string(name), curs));
232285
} catch (std::exception& e) {
233286
std::cerr << e.what() << std::endl;
234287
std::cerr <<"Using default cursor."<<std::endl;
235288
return;
236289
}
237-
238-
SDL_Surface* surf = SDLUtil::imageToSurface(decompressed, true);
239-
240-
//set the cursor and store it for later
241-
SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y);
242-
mCursorMap.insert(CursorMap::value_type(std::string(name), curs));
243-
244-
//clean up
245-
SDL_FreeSurface(surf);
246290
}
247291

248292
}

0 commit comments

Comments
 (0)