parent
9d9c7f291c
commit
685b8c82d0
|
@ -0,0 +1,97 @@
|
||||||
|
## Window creation for Retina displays
|
||||||
|
|
||||||
|
The file info.plist sets NSHighResolutionCapable to true. This is fine for High-DPI
|
||||||
|
and retina displays.
|
||||||
|
|
||||||
|
The `SDL_CreateWindow` is called with the flag `SDL_WINDOW_ALLOW_HIGHDPI`.
|
||||||
|
On Mac OS it means that, in source file `video/cocoa/SDL_cocoawindow.m`, from
|
||||||
|
function `Cocoa_CreateWindow`, SDL calls:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
/* highdpi will be TRUE below */
|
||||||
|
BOOL highdpi = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
|
||||||
|
[contentView setWantsBestResolutionOpenGLSurface:highdpi]
|
||||||
|
```
|
||||||
|
|
||||||
|
Documentation for `setWantsBestResolutionOpenGLSurface`:
|
||||||
|
|
||||||
|
https://developer.apple.com/documentation/appkit/nsview/1414938-wantsbestresolutionopenglsurface
|
||||||
|
|
||||||
|
with more details in "OpenGL Programming Guide for Mac", chapter
|
||||||
|
"Optimizing OpenGL for High Resolution":
|
||||||
|
|
||||||
|
https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/EnablingOpenGLforHighResolution/EnablingOpenGLforHighResolution.html#//apple_ref/doc/uid/TP40001987-CH1001-SW4
|
||||||
|
|
||||||
|
Citation from the official documentation:
|
||||||
|
|
||||||
|
You can opt in to high resolution by calling the method
|
||||||
|
`setWantsBestResolutionOpenGLSurface:` when you initialize the view, and
|
||||||
|
supplying YES as an argument:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
[self setWantsBestResolutionOpenGLSurface:YES];
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don’t opt in, the system magnifies the rendered results.
|
||||||
|
|
||||||
|
The wantsBestResolutionOpenGLSurface property is relevant only for views to
|
||||||
|
which an NSOpenGLContext object is bound. Its value does not affect the behavior
|
||||||
|
of other views. For compatibility, wantsBestResolutionOpenGLSurface defaults to
|
||||||
|
NO, providing a 1-pixel-per-point framebuffer regardless of the backing scale
|
||||||
|
factor for the display the view occupies. Setting this property to YES for a
|
||||||
|
given view causes AppKit to allocate a higher-resolution framebuffer when
|
||||||
|
appropriate for the backing scale factor and target display.
|
||||||
|
|
||||||
|
To function correctly with wantsBestResolutionOpenGLSurface set to YES, a view
|
||||||
|
must perform correct conversions between view units (points) and pixel units as
|
||||||
|
needed. For example, the common practice of passing the width and height of
|
||||||
|
[self bounds] to glViewport() will yield incorrect results at high resolution,
|
||||||
|
because the parameters passed to the glViewport() function must be in pixels. As
|
||||||
|
a result, you’ll get only partial instead of complete coverage of the render
|
||||||
|
surface. Instead, use the backing store bounds:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
[self convertRectToBacking:[self bounds]];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Coordinates
|
||||||
|
|
||||||
|
The SDL function `SDL_GL_GetDrawableSize` will provide the size of the underlying drawable
|
||||||
|
in pixels. From the `SDL_video.h` header.
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* \brief Get the size of a window's underlying drawable in pixels (for use
|
||||||
|
* with glViewport).
|
||||||
|
*
|
||||||
|
* \param window Window from which the drawable size should be queried
|
||||||
|
* \param w Pointer to variable for storing the width in pixels, may be NULL
|
||||||
|
* \param h Pointer to variable for storing the height in pixels, may be NULL
|
||||||
|
*
|
||||||
|
* This may differ from SDL_GetWindowSize() if we're rendering to a high-DPI
|
||||||
|
* drawable, i.e. the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a
|
||||||
|
* platform with high-DPI support (Apple calls this "Retina"), and not disabled
|
||||||
|
* by the SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetWindowSize()
|
||||||
|
* \sa SDL_CreateWindow()
|
||||||
|
*/
|
||||||
|
extern DECLSPEC void SDLCALL SDL_GL_GetDrawableSize(SDL_Window * window, int *w,
|
||||||
|
int *h);
|
||||||
|
```
|
||||||
|
|
||||||
|
In turns it calls `Cocoa_GL_GetDrawableSize` from source file
|
||||||
|
`video/cocoa/SDL_cocoaopengl.m`. The function use the method
|
||||||
|
`[contentView convertRectToBacking:viewport]`:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
|
||||||
|
/* This gives us the correct viewport for a Retina-enabled view, only
|
||||||
|
* supported on 10.7+. */
|
||||||
|
if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
|
||||||
|
viewport = [contentView convertRectToBacking:viewport];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
to give back the sizes in pixels.
|
|
@ -125,6 +125,9 @@ int main(int argc, char **argv) {
|
||||||
window = SDL_CreateWindow(
|
window = SDL_CreateWindow(
|
||||||
"", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8,
|
"", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8,
|
||||||
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
|
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
|
||||||
|
|
||||||
|
fprintf(stderr, "New window: %p\n", window); fflush(stderr);
|
||||||
|
|
||||||
init_window_icon();
|
init_window_icon();
|
||||||
ren_init(window);
|
ren_init(window);
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,11 @@ struct RenFont {
|
||||||
|
|
||||||
|
|
||||||
static SDL_Window *window;
|
static SDL_Window *window;
|
||||||
|
static SDL_Renderer *window_renderer = NULL;
|
||||||
|
static SDL_Texture *window_texture = NULL;
|
||||||
|
static SDL_Surface *window_surface = NULL;
|
||||||
|
static int window_w = -1, window_h = -1;
|
||||||
|
|
||||||
static FR_Clip_Area clip;
|
static FR_Clip_Area clip;
|
||||||
|
|
||||||
static void* check_alloc(void *ptr) {
|
static void* check_alloc(void *ptr) {
|
||||||
|
@ -61,6 +66,30 @@ static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static SDL_Surface *get_window_surface(SDL_Window *this_window) {
|
||||||
|
int w, h;
|
||||||
|
// fprintf(stderr, "get_window_surface: %p\n", this_window); fflush(stderr);
|
||||||
|
SDL_GL_GetDrawableSize(this_window, &w, &h);
|
||||||
|
// FIXME: check for errors ?
|
||||||
|
if (window_surface && w == window_w && h == window_h) {
|
||||||
|
fprintf(stderr, "get_window_surface: return current surface: %p\n", window_surface); fflush(stderr);
|
||||||
|
return window_surface;
|
||||||
|
}
|
||||||
|
if (window_surface) {
|
||||||
|
fprintf(stderr, "going to free: %p\n", window_surface); fflush(stderr);
|
||||||
|
SDL_FreeSurface(window_surface);
|
||||||
|
}
|
||||||
|
window_surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 24, SDL_PIXELFORMAT_BGR24);
|
||||||
|
|
||||||
|
fprintf(stderr, "NEW surface: %p, size: %d %d\n", window_surface, w, h); fflush(stderr);
|
||||||
|
|
||||||
|
window_w = w;
|
||||||
|
window_h = h;
|
||||||
|
|
||||||
|
return window_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_cp_replace_init(CPReplaceTable *rep_table) {
|
void ren_cp_replace_init(CPReplaceTable *rep_table) {
|
||||||
rep_table->size = 0;
|
rep_table->size = 0;
|
||||||
rep_table->replacements = NULL;
|
rep_table->replacements = NULL;
|
||||||
|
@ -95,18 +124,42 @@ void ren_cp_replace_add(CPReplaceTable *rep_table, const char *src, const char *
|
||||||
void ren_init(SDL_Window *win) {
|
void ren_init(SDL_Window *win) {
|
||||||
assert(win);
|
assert(win);
|
||||||
window = win;
|
window = win;
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
SDL_Surface *surf = get_window_surface(window); //SDL_GetWindowSurface(window);
|
||||||
|
fprintf(stderr, "New surface %p\n", surf); fflush(stderr);
|
||||||
ren_set_clip_rect( (RenRect) { 0, 0, surf->w, surf->h } );
|
ren_set_clip_rect( (RenRect) { 0, 0, surf->w, surf->h } );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_update_rects(RenRect *rects, int count) {
|
void ren_update_rects(RenRect *rects, int count) {
|
||||||
|
#if 0
|
||||||
SDL_UpdateWindowSurfaceRects(window, (SDL_Rect*) rects, count);
|
SDL_UpdateWindowSurfaceRects(window, (SDL_Rect*) rects, count);
|
||||||
|
#endif
|
||||||
|
fprintf(stderr, "ren_update_rects\n"); fflush(stderr);
|
||||||
static bool initial_frame = true;
|
static bool initial_frame = true;
|
||||||
if (initial_frame) {
|
if (initial_frame) {
|
||||||
SDL_ShowWindow(window);
|
SDL_ShowWindow(window);
|
||||||
initial_frame = false;
|
initial_frame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int w, h;
|
||||||
|
SDL_GL_GetDrawableSize(window, &w, &h);
|
||||||
|
|
||||||
|
if (window_renderer && (w != window_w || h != window_h)) {
|
||||||
|
SDL_DestroyTexture(window_texture);
|
||||||
|
SDL_DestroyRenderer(window_renderer);
|
||||||
|
window_renderer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window_renderer) {
|
||||||
|
window_renderer = SDL_CreateRenderer(window, -1, 0);
|
||||||
|
// SDL_CreateTextureFromSurface(sdlRenderer, mySurface);
|
||||||
|
window_texture = SDL_CreateTexture(window_renderer, SDL_PIXELFORMAT_BGR24, SDL_TEXTUREACCESS_STREAMING, w, h);
|
||||||
|
fprintf(stderr, "got new renderer and texture: %p %p\n", window_renderer, window_texture); fflush(stderr);
|
||||||
|
}
|
||||||
|
// FIXME: we ignore the rects here.
|
||||||
|
SDL_UpdateTexture(window_texture, NULL, window_surface->pixels, window_w * 3);
|
||||||
|
SDL_RenderCopy(window_renderer, window_texture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(window_renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,7 +172,7 @@ void ren_set_clip_rect(RenRect rect) {
|
||||||
|
|
||||||
|
|
||||||
void ren_get_size(int *x, int *y) {
|
void ren_get_size(int *x, int *y) {
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
SDL_Surface *surf = get_window_surface(window); //SDL_GetWindowSurface(window);
|
||||||
*x = surf->w;
|
*x = surf->w;
|
||||||
*y = surf->h;
|
*y = surf->h;
|
||||||
}
|
}
|
||||||
|
@ -278,7 +331,10 @@ void ren_draw_rect(RenRect rect, RenColor color) {
|
||||||
x2 = x2 > clip.right ? clip.right : x2;
|
x2 = x2 > clip.right ? clip.right : x2;
|
||||||
y2 = y2 > clip.bottom ? clip.bottom : y2;
|
y2 = y2 > clip.bottom ? clip.bottom : y2;
|
||||||
|
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
// fprintf(stderr, "ren_draw_rect: clipped rect: (%d, %d) (%d, %d)\n", x1, y1, x2, y2);
|
||||||
|
|
||||||
|
// SDL_Surface *surf = SDL_GetWindowSurface(window);
|
||||||
|
SDL_Surface *surf = get_window_surface(window);
|
||||||
RenColor *d = (RenColor*) surf->pixels;
|
RenColor *d = (RenColor*) surf->pixels;
|
||||||
d += x1 + y1 * surf->w;
|
d += x1 + y1 * surf->w;
|
||||||
int dr = surf->w - (x2 - x1);
|
int dr = surf->w - (x2 - x1);
|
||||||
|
@ -290,6 +346,8 @@ void ren_draw_rect(RenRect rect, RenColor color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: this function is never used
|
||||||
|
#if 0
|
||||||
void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) {
|
void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) {
|
||||||
if (color.a == 0) { return; }
|
if (color.a == 0) { return; }
|
||||||
|
|
||||||
|
@ -304,7 +362,7 @@ void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* draw */
|
/* draw */
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
SDL_Surface *surf = get_window_surface(window); //SDL_GetWindowSurface(window);
|
||||||
RenColor *s = image->pixels;
|
RenColor *s = image->pixels;
|
||||||
RenColor *d = (RenColor*) surf->pixels;
|
RenColor *d = (RenColor*) surf->pixels;
|
||||||
s += sub->x + sub->y * image->width;
|
s += sub->x + sub->y * image->width;
|
||||||
|
@ -322,6 +380,7 @@ void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color)
|
||||||
s += sr;
|
s += sr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int codepoint_replace(CPReplaceTable *rep_table, unsigned *codepoint) {
|
static int codepoint_replace(CPReplaceTable *rep_table, unsigned *codepoint) {
|
||||||
for (int i = 0; i < rep_table->size; i++) {
|
for (int i = 0; i < rep_table->size; i++) {
|
||||||
|
@ -340,7 +399,7 @@ void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int
|
||||||
{
|
{
|
||||||
const char *p = text;
|
const char *p = text;
|
||||||
unsigned codepoint;
|
unsigned codepoint;
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
SDL_Surface *surf = get_window_surface(window); // SDL_GetWindowSurface(window);
|
||||||
const FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b };
|
const FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b };
|
||||||
while (*p) {
|
while (*p) {
|
||||||
FR_Color color_rep;
|
FR_Color color_rep;
|
||||||
|
|
Loading…
Reference in New Issue