looking-glass/client/renderers/basic.c

168 lines
No EOL
3.7 KiB
C

#include "lg-renderer.h"
#include <stdbool.h>
#include <stdint.h>
#include <SDL2/SDL.h>
#include "debug.h"
#include "memcpySSE.h"
struct LGR_Basic
{
bool initialized;
LG_RendererFormat format;
size_t texSize;
size_t dataWidth;
SDL_Renderer * renderer;
SDL_Texture * texture;
SDL_Rect destRect;
};
const char * lgr_basic_get_name()
{
return "Basic";
}
bool lgr_basic_initialize(void ** opaque, const LG_RendererParams params, const LG_RendererFormat format)
{
// create our local storage
*opaque = malloc(sizeof(struct LGR_Basic));
if (!*opaque)
{
DEBUG_INFO("Failed to allocate %lu bytes", sizeof(struct LGR_Basic));
return false;
}
memset(*opaque, 0, sizeof(struct LGR_Basic));
struct LGR_Basic * this = (struct LGR_Basic *)*opaque;
this->renderer = SDL_CreateRenderer(params.window, -1,
SDL_RENDERER_ACCELERATED |
SDL_RENDERER_PRESENTVSYNC
);
if (!this->renderer)
{
DEBUG_ERROR("Failed to create renderer");
return false;
}
Uint32 sdlFormat;
switch(format.bpp)
{
case 24:
sdlFormat = SDL_PIXELFORMAT_RGB24;
break;
case 32:
sdlFormat = SDL_PIXELFORMAT_ARGB8888;
break;
default:
DEBUG_ERROR("Unsupported bpp");
return false;
}
// calculate the texture size in bytes
this->texSize = format.height * format.pitch;
// create the target texture
this->texture = SDL_CreateTexture(
this->renderer,
sdlFormat,
SDL_TEXTUREACCESS_STREAMING,
format.width,
format.height
);
if (!this->texture)
{
DEBUG_ERROR("SDL_CreateTexture failed");
return false;
}
memcpy(&this->format, &format, sizeof(LG_RendererFormat));
this->dataWidth = this->format.width * (this->format.bpp / 8);
this->initialized = true;
return true;
}
void lgr_basic_deinitialize(void * opaque)
{
struct LGR_Basic * this = (struct LGR_Basic *)opaque;
if (!this)
return;
if (this->texture)
SDL_DestroyTexture(this->texture);
if (this->renderer)
SDL_DestroyRenderer(this->renderer);
free(this);
}
bool lgr_basic_is_compatible(void * opaque, const LG_RendererFormat format)
{
const struct LGR_Basic * this = (struct LGR_Basic *)opaque;
if (!this || !this->initialized)
return false;
return (memcmp(&this->format, &format, sizeof(LG_RendererFormat)) == 0);
}
void lgr_basic_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect)
{
struct LGR_Basic * this = (struct LGR_Basic *)opaque;
if (!this || !this->initialized)
return;
this->destRect.x = destRect.x;
this->destRect.y = destRect.y;
this->destRect.w = destRect.w;
this->destRect.h = destRect.h;
}
bool lgr_basic_render(void * opaque, const uint8_t * data, bool resample)
{
struct LGR_Basic * this = (struct LGR_Basic *)opaque;
if (!this || !this->initialized)
return false;
int pitch;
uint8_t * dest;
if (SDL_LockTexture(this->texture, NULL, (void**)&dest, &pitch) != 0)
{
DEBUG_ERROR("Failed to lock the texture for update");
return false;
}
if (pitch == this->format.pitch)
memcpySSE(dest, data, this->texSize);
else
{
for(unsigned int y = 0; y < this->format.height; ++y)
{
memcpySSE(dest, data, this->dataWidth);
dest += pitch;
data += this->format.pitch;
}
}
SDL_UnlockTexture(this->texture);
SDL_RenderCopy(this->renderer, this->texture, NULL, &this->destRect);
SDL_RenderPresent(this->renderer);
return true;
}
const LG_Renderer LGR_Basic =
{
.get_name = lgr_basic_get_name,
.initialize = lgr_basic_initialize,
.deinitialize = lgr_basic_deinitialize,
.is_compatible = lgr_basic_is_compatible,
.on_resize = lgr_basic_on_resize,
.render = lgr_basic_render
};