Inverting draw mode?

I’m porting some legacy Mac code to SDL, since Apple Computer has yanked away the C++ interfaces from beneath me.

One thing I was using was the inverting draw mode. This means that the new image is drawn onto the window or drawing surface using an exclusive-or operation at the bit level. It has the convenient property that if you draw the same object onto the same surface twice in this mode, it vanishes, restoring the surface to its previous state. This has some cool artistic uses, and is also useful for compatibility with some legacy code.

I’m not seeing it in the documentation, and I’m aware that modern graphics cards may not encourage such an operation onto the screen, but it sure would be nice to be able to do this to a Texture. Is this at all supported? If not, I would urge its adoption as an additional “Blending mode”.

joymaker wrote:

Is this at all supported? If not, I would urge its adoption as an additional “Blending mode”.

I rely on it. The solution I use is to force OpenGL (or GLES 1.0) when it’s not the default:

Code:
SDL_SetHint (SDL_HINT_RENDER_DRIVER, “opengl”) ;
window = SDL_CreateWindow(…, SDL_WINDOW_OPENGL…) ;

then you can enable the wanted drawing mode using:

Code:
glEnable (GL_COLOR_LOGIC_OP) ;
glLogicOp (GL_XOR) ;

Works perfectly for me on Windows, Linux, Mac OS and Android. It’s unfortunate that support for glLogicOp was dropped from GLES 2.0 so on platforms which can’t run full OpenGL you are forced to use the legacy GLES 1.0.

Richard.

Does GLSL ES have bitwise operators? I would think you could invert in a
shader.

Jonny DOn Thu, Dec 8, 2016 at 7:12 AM, rtrussell wrote:

joymaker wrote:

Is this at all supported? If not, I would urge its adoption as an
additional “Blending mode”.

I rely on it. The solution I use is to force OpenGL (or GLES 1.0) when
it’s not the default:

Code:

SDL_SetHint (SDL_HINT_RENDER_DRIVER, “opengl”) ;
window = SDL_CreateWindow(…, SDL_WINDOW_OPENGL…) ;

then you can enable the wanted drawing mode using:

Code:

glEnable (GL_COLOR_LOGIC_OP) ;
glLogicOp (GL_XOR) ;

Works perfectly for me on Windows, Linux, Mac OS and Android. It’s
unfortunate that support for glLogicOp was dropped from GLES 2.0 so on
platforms which can’t run full OpenGL you are forced to use the legacy GLES
1.0.

Richard.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Reading from the video memory is always a bad idea.
Why don’t you make your own screen buffer, do your drawing in it, then at the end you put it in a texture and render it?

EternalLands - that’s what I was planning on doing anyway, I just didn’t see any primitive operators with which to do it. What I don’t want to do if I don’t have to is reinvent the rectangle drawing primitive from scratch, just to do this.

Richard ??? thanks, that sounds like a good plan. So I think you’re telling me that setting up the OpenGL LogicOp will modify ALL drawing done through the window, SDL primitives as well as OpenGL primitives. Right? (And is there any significant downside to specifying “opengl” as my driver, instead of the usual default?)

Thanks,
Ken

joymaker wrote:

So I think you’re telling me that setting up the OpenGL LogicOp will modify ALL drawing done through the window, SDL primitives as well as OpenGL primitives. Right?

Yes, SDL drawing operations such as SDL_RenderDrawPoint, SDL_RenderDrawLine and those in SDL_gfx will be affected by the LogicOp. For safety I would recommend enabling and setting the LogicOp only around such calls rather than leaving it active for longer periods, just in case it interferes with anything else in SDL.

(And is there any significant downside to specifying “opengl” as my driver, instead of the usual default?)

Only in Windows is OpenGL/GLES not the default, I think, and I’ve not noticed any significant impact from forcing its use.

Richard.

Here’s the SDL_gfx demo modified to use exclusive-or plotting:

Code:
// Demo of exclusive-or plotting by Richard Russell http://www.rtrussell.co.uk/

#include <stdio.h>
#include “SDL2_gfxPrimitives.h”

#define WIDTH 640
#define HEIGHT 480
#define GL_COLOR_LOGIC_OP 0xBF2
#define GL_XOR 0x1506

#ifdef WINDOWS
void (__stdcall *glEnable) (int) ;
void (__stdcall *glLogicOp) (int) ;
void (__stdcall *glDisable) (int) ;
#else
void (*glEnable) (int) ;
void (*glLogicOp) (int) ;
void (*glDisable) (int) ;
#endif

int main(int argc, char* argv[])
{

if (SDL_Init(SDL_INIT_VIDEO)) 
{ 
    printf ("SDL_Init Error: %s", SDL_GetError()); 
    return 1; 
} 

SDL_SetHint (SDL_HINT_RENDER_DRIVER, "opengl") ;

SDL_Window *window = SDL_CreateWindow("SDL2_gfx test", 100, 100, WIDTH, HEIGHT, SDL_WINDOW_OPENGL); 
if (window == NULL) 
{ 
    printf ("SDL_CreateWindow Error: %s", SDL_GetError()); 
    SDL_Quit(); 
    return 2; 
} 

glLogicOp = SDL_GL_GetProcAddress("glLogicOp") ;
glEnable  = SDL_GL_GetProcAddress("glEnable") ;
glDisable = SDL_GL_GetProcAddress("glDisable") ;

SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 
if (renderer == NULL) 
{ 
    SDL_DestroyWindow(window); 
    printf ("SDL_CreateRenderer Error: %s", SDL_GetError()); 
    SDL_Quit(); 
    return 3; 
} 

SDL_Event e; 

int quit = 0; 
while (!quit) 
{ 
    if (SDL_PollEvent(&e)) 
    { 
        if (e.type == SDL_QUIT) 
            quit = 1; 
    } 
    SDL_SetRenderDrawColor(renderer, 0, 0, 0xFF, 0xFF); 
    SDL_RenderClear(renderer); 

    glEnable (GL_COLOR_LOGIC_OP) ;
    glLogicOp (GL_XOR) ;

    thickLineColor(renderer, 0, 0, WIDTH, HEIGHT, 20, 0xFFFFFFFF) ; 
    thickLineColor(renderer, 0, HEIGHT, WIDTH, 0, 20, 0xFFFFFFFF) ; 
    circleColor(renderer, WIDTH/2, HEIGHT/2, 80, 0xFF00FF00); 
    filledCircleColor(renderer, WIDTH/2, HEIGHT/2, 60, 0xFF0000FF); 

    glDisable (GL_COLOR_LOGIC_OP) ;

    SDL_RenderPresent(renderer); 
    SDL_Delay(10); 
} 

SDL_DestroyRenderer(renderer); 
SDL_DestroyWindow(window); 
SDL_Quit(); 
return 0; 

}