aliens

Author Topic: SpecialBlit to convert from 8 bit to 32 bit show weird graphics  (Read 1998 times)

Offline Skybuck

  • Colonel
  • ****
  • Posts: 223
    • View Profile
This is what I got so far:

SpecialBlit.h:

Code: [Select]
#pragma once

#include <SDL.h>

int SpecialBlit
(
SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect
);

void SpecialGradientTest( SDL_Surface *ParaSurface );

SpecialBlit.cpp

Code copied from SDL and modified:

Code: [Select]
#include "SpecialBlit.h"

// Skybuck: re-use clipping from SDL_UpperBlit

// maybe a custom blitter is possible, but for now it seems a recompile of SDL would be needed.
/** typedef for private surface blitting functions */
// typedef int (*SDL_blit)(struct SDL_Surface *src, SDL_Rect *srcrect,
// struct SDL_Surface *dst, SDL_Rect *dstrect);




/*
 * Set up a blit between two surfaces -- split into three parts:
 * The upper part, SDL_UpperBlit(), performs clipping and rectangle
 * verification.  The lower part is a pointer to a low level
 * accelerated blitting function.
 *
 * These parts are separated out and each used internally by this
 * library in the optimimum places.  They are exported so that if
 * you know exactly what you are doing, you can optimize your code
 * by calling the one(s) you need.
 */
 /*
int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect)
{
SDL_blit do_blit;
SDL_Rect hw_srcrect;
SDL_Rect hw_dstrect;

// Check to make sure the blit mapping is valid
if ( (src->map->dst != dst) ||
             (src->map->dst->format_version != src->map->format_version) ) {
if ( SDL_MapSurface(src, dst) < 0 ) {
return(-1);
}
}

// Figure out which blitter to use
if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
if ( src == SDL_VideoSurface ) {
hw_srcrect = *srcrect;
hw_srcrect.x += current_video->offset_x;
hw_srcrect.y += current_video->offset_y;
srcrect = &hw_srcrect;
}
if ( dst == SDL_VideoSurface ) {
hw_dstrect = *dstrect;
hw_dstrect.x += current_video->offset_x;
hw_dstrect.y += current_video->offset_y;
dstrect = &hw_dstrect;
}
do_blit = src->map->hw_blit;
} else {
do_blit = src->map->sw_blit;
}
return(do_blit(src, srcrect, dst, dstrect));
}
*/


int SDL_LowerBlitSpecial
(
SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect
)
{
int x, y;
int w, h;
int sp, dp;

Uint8 *SrcPointer;
SDL_Color *DstPointer;

Uint8 SrcColor;
SDL_Color DstColor;
// int SrcOffset;
// int DstOffset;
int offset;

w = src->w;
h = src->h;
sp = src->pitch;
dp = dst->pitch;

for (y=0; y<h; y++)
{
for (x=0; x<w; x++)
{
// SrcOffset = y * sp + x;
// DstOffset = y * dp + x * 4;

// pointers below already multiply by data structure width so don't do it in formulas below =D

// SrcOffset = y * w + x;
// DstOffset = y * w + x;
offset = y * w + x;

SrcPointer = (Uint8*) src->pixels;
DstPointer = (SDL_Color*) dst->pixels;

SrcColor = SrcPointer[offset];

if (SrcColor != 0)
{
// test color should be replaced later with palette lookup, I don't think this is the cause of the problems, since width and height seems off.
DstColor.r = SrcColor;
DstColor.g = SrcColor;
DstColor.b = SrcColor;

DstPointer[offset] = DstColor;
}
}
}
return 1;
}

int SpecialBlit
(
SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect
)
{
    SDL_Rect fulldst;
int srcx, srcy, w, h;

/* Make sure the surfaces aren't locked */
if ( ! src || ! dst )
{
SDL_SetError("SDL_UpperBlit: passed a NULL surface");
return(-1);
}
if ( src->locked || dst->locked )
{
SDL_SetError("Surfaces must not be locked during blit");
return(-1);
}

/* If the destination rectangle is NULL, use the entire dest surface */
if ( dstrect == NULL )
{
    fulldst.x = fulldst.y = 0;
dstrect = &fulldst;
}

/* clip the source rectangle to the source surface */
if(srcrect)
{
    int maxw, maxh;

srcx = srcrect->x;
w = srcrect->w;
if(srcx < 0)
{
    w += srcx;
dstrect->x -= srcx;
srcx = 0;
}
maxw = src->w - srcx;
if(maxw < w) w = maxw;

srcy = srcrect->y;
h = srcrect->h;
if(srcy < 0)
{
    h += srcy;
dstrect->y -= srcy;
srcy = 0;
}
maxh = src->h - srcy;
if(maxh < h) h = maxh;
   
} else
{
    srcx = srcy = 0;
w = src->w;
h = src->h;
}

/* clip the destination rectangle against the clip rectangle */
{
    SDL_Rect *clip = &dst->clip_rect;
int dx, dy;

dx = clip->x - dstrect->x;
if(dx > 0)
{
w -= dx;
dstrect->x += dx;
srcx += dx;
}
dx = dstrect->x + w - clip->x - clip->w;
if(dx > 0) w -= dx;

dy = clip->y - dstrect->y;
if(dy > 0)
{
h -= dy;
dstrect->y += dy;
srcy += dy;
}
dy = dstrect->y + h - clip->y - clip->h;
if(dy > 0) h -= dy;
}

if(w > 0 && h > 0)
{
    SDL_Rect sr;
    sr.x = srcx;
sr.y = srcy;
sr.w = dstrect->w = w;
sr.h = dstrect->h = h;
return SDL_LowerBlitSpecial(src, &sr, dst, dstrect);
}
dstrect->w = dstrect->h = 0;
return 0;
}


void SpecialGradientTest( SDL_Surface *ParaSurface )
{
int x, y;
int w, h, p, b;
int offset;
SDL_Color color;
SDL_Color *pointer;

h = ParaSurface->h;
w = ParaSurface->w;
p = ParaSurface->pitch;
b = ParaSurface->format->BytesPerPixel;
pointer = (SDL_Color*)(ParaSurface->pixels);

SDL_LockSurface( ParaSurface );

for (y=0; y<h; y++)
{
for (x=0; x<w; x++)
{
offset = y * w + x;

color.r = x & 255;
color.b = y & 255;
color.g = 0;

pointer[offset] = color;

// pointer = (SDL_Color *)ParaSurface->pixels + (y * ParaSurface->pitch + x * ParaSurface->format->BytesPerPixel);
// *pointer = color;
}
}

    SDL_UnlockSurface( ParaSurface );
}

Trying to get OpenXcom surface to convert from 8 to 32 bit when it's encountered:

Code: [Select]
/**
 * Blits this surface onto another one, with its position
 * relative to the top-left corner of the target surface.
 * The cropping rectangle controls the portion of the surface
 * that is blitted.
 * @param surface Pointer to surface to blit onto.
 */
void Surface::blit(Surface *surface)
{
SDL_Surface *SrcSurface;
SDL_Surface *DstSurface;
SDL_Surface *ConvertedSurface;

if (_visible && !_hidden)
{
if (_redraw)
draw();

SDL_Rect* cropper;
SDL_Rect target;
if (_crop.w == 0 && _crop.h == 0)
{
cropper = 0;
}
else
{
cropper = &_crop;
}
target.x = getX();
target.y = getY();

SrcSurface = _surface;
DstSurface = surface->getSurface();

if
(
(SrcSurface->format->BitsPerPixel == 8) &&
(DstSurface->format->BitsPerPixel == 32)
)
{
// do something special
SpecialBlit(_surface, cropper, surface->getSurface(), &target);
} else
{
// assume 8 bits to 8 bits.
SDL_BlitSurface(_surface, cropper, surface->getSurface(), &target);
}
}
}

Tell OpenXcom to use 32 bit surface.

Code: [Select]
void Screen::resetDisplay(bool resetVideo)
{
int width = Options::displayWidth;
int height = Options::displayHeight;
#ifdef __linux__
Uint32 oldFlags = _flags;
#endif
makeVideoFlags();

if (!_surface || (_surface->getSurface()->format->BitsPerPixel != _bpp ||
_surface->getSurface()->w != _baseWidth ||
_surface->getSurface()->h != _baseHeight)) // don't reallocate _surface if not necessary, it's a waste of CPU cycles
{
if (_surface) delete _surface;
// _surface = new Surface(_baseWidth, _baseHeight, 0, 0, Screen::use32bitScaler() ? 32 : 8); // only HQX/XBRZ needs 32bpp for this surface; the OpenGL class has its own 32bpp buffer
_surface = new Surface(_baseWidth, _baseHeight, 0, 0, 32); // only HQX/XBRZ needs 32bpp for this surface; the OpenGL class has its own 32bpp buffer
if (_surface->getSurface()->format->BitsPerPixel == 8) _surface->setPalette(deferredPalette);
}
« Last Edit: May 30, 2022, 07:56:31 pm by Skybuck »

Offline Skybuck

  • Colonel
  • ****
  • Posts: 223
    • View Profile
Re: SpecialBlit to convert from 8 bit to 32 bit show weird graphics
« Reply #1 on: May 30, 2022, 08:01:47 pm »
Small little code improvement, locking don't help, width/height seems off:

Code: [Select]
int SDL_LowerBlitSpecial
(
SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect
)
{
int x, y;
int w, h;
int sp, dp;

Uint8 *SrcPointer;
SDL_Color *DstPointer;

Uint8 SrcColor;
SDL_Color DstColor;
// int SrcOffset;
// int DstOffset;
int offset;

w = src->w;
h = src->h;
sp = src->pitch;
dp = dst->pitch;

SDL_LockSurface( src );
SDL_LockSurface( dst );

for (y=0; y<h; y++)
{
for (x=0; x<w; x++)
{
// SrcOffset = y * sp + x;
// DstOffset = y * dp + x * 4;

// pointers below already multiply by data structure width so don't do it in formulas below =D

// SrcOffset = y * w + x;
// DstOffset = y * w + x;
offset = y * w + x;

SrcPointer = (Uint8*) src->pixels;
DstPointer = (SDL_Color*) dst->pixels;

SrcColor = SrcPointer[offset];

if (SrcColor != 0)
{
DstColor.r = SrcColor;
DstColor.g = SrcColor;
DstColor.b = SrcColor;

DstPointer[offset] = DstColor;
}
}
}

    SDL_UnlockSurface( dst );
SDL_UnlockSurface( src );

return 1;
}

Hmm perhaps src and dst rect should be used for offsets... will give it a try ! ;)

Offline Skybuck

  • Colonel
  • ****
  • Posts: 223
    • View Profile
Re: SpecialBlit to convert from 8 bit to 32 bit show weird graphics
« Reply #2 on: May 30, 2022, 08:10:15 pm »
Width and height seems better, though graphics still weird, it also seems clipped improperly.

Code: [Select]
int SDL_LowerBlitSpecial
(
SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect
)
{
int x, y;
int w, h;
int sp, dp;

Uint8 *SrcPointer;
SDL_Color *DstPointer;

Uint8 SrcColor;
SDL_Color DstColor;

int SrcW, SrcH;
int DstW, DstH;

int SrcX, SrcY;
int DstX, DstY;

int SrcOffset;
int DstOffset;


SrcW = src->w;
SrcH = src->h;

DstW = dst->w;
DstH = dst->h;

sp = src->pitch;
dp = dst->pitch;

SDL_LockSurface( src );
SDL_LockSurface( dst );

w = SrcW;
h = SrcH;
for (y=0; y<h; y++)
{
for (x=0; x<w; x++)
{
SrcX = srcrect->x + x;
SrcY = srcrect->y + y;

DstX = dstrect->x + x;
DstY = dstrect->y + y;


// SrcOffset = y * sp + x;
// DstOffset = y * dp + x * 4;

// pointers below already multiply by data structure width so don't do it in formulas below =D

SrcOffset = SrcY * SrcW + SrcX;
DstOffset = DstY * DstW + DstX;

SrcPointer = (Uint8*) src->pixels;
DstPointer = (SDL_Color*) dst->pixels;

SrcColor = SrcPointer[SrcOffset];

if (SrcColor != 0)
{
DstColor.r = SrcColor;
DstColor.g = SrcColor;
DstColor.b = SrcColor;

DstPointer[DstOffset] = DstColor;
}
}
}

    SDL_UnlockSurface( dst );
SDL_UnlockSurface( src );

return 1;
}

Offline Skybuck

  • Colonel
  • ****
  • Posts: 223
    • View Profile
Re: SpecialBlit to convert from 8 bit to 32 bit show weird graphics
« Reply #3 on: May 30, 2022, 08:24:47 pm »
Seems like cropper can be null... with new SpecialBlitV2 it's always null... weird stuff

Code: [Select]
int SpecialBlitV2
(
SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect
)
{
int x, y;
int w, h;
int sp, dp;

Uint8 *SrcPointer;
SDL_Color *DstPointer;

Uint8 SrcColor;
SDL_Color DstColor;

int SrcW, SrcH;
int DstW, DstH;

int SrcX, SrcY;
int DstX, DstY;

int SrcOffset;
int DstOffset;


SrcW = src->w;
SrcH = src->h;

DstW = dst->w;
DstH = dst->h;

sp = src->pitch;
dp = dst->pitch;

SDL_LockSurface( src );
SDL_LockSurface( dst );

w = SrcW;
h = SrcH;
for (y=0; y<h; y++)
{
for (x=0; x<w; x++)
{
SrcX = srcrect->x + x;
SrcY = srcrect->y + y;

DstX = dstrect->x + x;
DstY = dstrect->y + y;


// SrcOffset = y * sp + x;
// DstOffset = y * dp + x * 4;

// pointers below already multiply by data structure width so don't do it in formulas below =D

SrcOffset = SrcY * SrcW + SrcX;
DstOffset = DstY * DstW + DstX;

SrcPointer = (Uint8*) src->pixels;
DstPointer = (SDL_Color*) dst->pixels;

SrcColor = SrcPointer[SrcOffset];

if
(
(DstX >= 0) && (DstX < DstW) &&
(DstY >= 0) && (DstY < DstH)
)
{

//if (SrcColor != 0)
{
DstColor.r = SrcColor;
DstColor.g = SrcColor;
DstColor.b = SrcColor;

DstPointer[DstOffset] = DstColor;
}
}
}
}

    SDL_UnlockSurface( dst );
SDL_UnlockSurface( src );

return 1;
}

Apperently SDL_UpperBlit is doing something to cropper or something.

Perhaps this code is missing in above try out:

Code: [Select]
    SDL_Rect sr;
    sr.x = srcx;
sr.y = srcy;
sr.w = dstrect->w = w;
sr.h = dstrect->h = h;
return SDL_LowerBlitSpecial(src, &sr, dst, dstrect); which should now be replaced with specialblitv2


This is null reference, hard to spot, sloppy code:

      SDL_Rect* cropper;
      SDL_Rect target;
      if (_crop.w == 0 && _crop.h == 0)
      {
         cropper = 0;  // replace with NULL makes it more clear ?!
      }

Conclusion V2 not necessary.

_crop is set wrongly somewhere.

code calls getCrop()

Most likely candidate of wrong setting is Window::Draw()

which seems to call getWidth getHeight and such.

Which are most likely set by

Window constructor.

I see a lot of Window 320, 200 calls and such... hmm...
« Last Edit: May 30, 2022, 08:34:45 pm by Skybuck »

Offline Skybuck

  • Colonel
  • ****
  • Posts: 223
    • View Profile
Re: SpecialBlit to convert from 8 bit to 32 bit show weird graphics
« Reply #4 on: May 30, 2022, 08:45:57 pm »
My lastest attempt so far:

Code: [Select]
/**
 * Blits this surface onto another one, with its position
 * relative to the top-left corner of the target surface.
 * The cropping rectangle controls the portion of the surface
 * that is blitted.
 * @param surface Pointer to surface to blit onto.
 */
void Surface::blit(Surface *surface)
{
SDL_Surface *SrcSurface;
SDL_Surface *DstSurface;
SDL_Surface *ConvertedSurface;

if (_visible && !_hidden)
{
if (_redraw)
draw();

SDL_Rect* cropper;
SDL_Rect target;
if (_crop.w == 0 && _crop.h == 0)
{
cropper = 0;
}
else
{
cropper = &_crop;
}
target.x = getX();
target.y = getY();

SrcSurface = _surface;
DstSurface = surface->getSurface();

if
(
(SrcSurface->format->BitsPerPixel == 8) &&
(DstSurface->format->BitsPerPixel == 32)
)
{
// do something special
// SpecialBlit(_surface, cropper, surface->getSurface(), &target);
SpecialBlitV2(_surface, surface->getSurface(), &target);
} else
{
// assume 8 bits to 8 bits.
SDL_BlitSurface(_surface, cropper, surface->getSurface(), &target);
}
}
}

Code: [Select]
int SpecialBlitV2
(
SDL_Surface *src,
SDL_Surface *dst, SDL_Rect *dstrect
)
{
int x, y;
int w, h;
int sp, dp;

Uint8 *SrcPointer;
SDL_Color *DstPointer;

Uint8 SrcColor;
SDL_Color DstColor;

int SrcW, SrcH;
int DstW, DstH;

int SrcX, SrcY;
int DstX, DstY;

int SrcOffset;
int DstOffset;

SrcW = src->w;
SrcH = src->h;

DstW = dst->w;
DstH = dst->h;

sp = src->pitch;
dp = dst->pitch;

SDL_LockSurface( src );
SDL_LockSurface( dst );

w = SrcW;
h = SrcH;
for (y=0; y<h; y++)
{
for (x=0; x<w; x++)
{
SrcX = x;
SrcY = y;

DstX = dstrect->x + x;
DstY = dstrect->y + y;


// SrcOffset = y * sp + x;
// DstOffset = y * dp + x * 4;

// pointers below already multiply by data structure width so don't do it in formulas below =D

SrcOffset = SrcY * SrcW + SrcX;
DstOffset = DstY * DstW + DstX;

SrcPointer = (Uint8*) src->pixels;
DstPointer = (SDL_Color*) dst->pixels;

SrcColor = SrcPointer[SrcOffset];

if
(
(DstX >= 0) && (DstX < DstW) &&
(DstY >= 0) && (DstY < DstH)
)
{

//if (SrcColor != 0)
{
DstColor.r = SrcColor;
DstColor.g = SrcColor;
DstColor.b = SrcColor;

DstPointer[DstOffset] = DstColor;
}
}
}
}

    SDL_UnlockSurface( dst );
SDL_UnlockSurface( src );

return 1;
}

I managed to accidently click load and thus I could play a game circumventing the ok button, but graphics fucked up.

SDL is biggest garbage ever... it obstructs VGA graphics completely, completely unnecessary library that complexifies more than it solves.

https://github.com/SkybuckFlying/OpenXcom/tree/TryCustomBlit

My new attempt will be a new branch to remove this SDL garbage. SDL should never be used for anything.

Tried to remove SDL and reduced it down to 5000 build errors, can probably be reduced quickly most build errors the same:

https://github.com/SkybuckFlying/OpenXcom/tree/RemoveSDLGarbage

SDLKey replaced by ControlKey.

Header files should include some BasicTypes.h which includes IntegerTypes.h Color.h and so forth now probably Rect.h needed.

Going to abort for now hoping for an easier solution, maybe this scaler thing... zoom in thing. Weird how 1600x900 is shown in surface blit and such.. hmmm... Maybe need to run the game in 320x200 configuration settings to get some better results... don't know where config file is... the game tends to "scan a lot" and pull data out of thing air/from some harddisk folder somewhere lol.
« Last Edit: May 30, 2022, 09:42:27 pm by Skybuck »