Add system that renders "cheap" "tiles" without color keying
The game appears to render level tiles as 16x16 pixel tiles, and many of these do not require any transparency. So we now compute which tiles are completely opaque and store those in a set, so that when we draw them we can skip color keying.
This commit is contained in:
parent
2928b8a362
commit
62898c85f8
1 changed files with 94 additions and 0 deletions
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "../Rendering.h"
|
#include "../Rendering.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -14,12 +16,16 @@
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
|
int surfaceCount = 0;
|
||||||
|
|
||||||
typedef struct RenderBackend_Surface
|
typedef struct RenderBackend_Surface
|
||||||
{
|
{
|
||||||
unsigned char *pixels;
|
unsigned char *pixels;
|
||||||
size_t width;
|
size_t width;
|
||||||
size_t height;
|
size_t height;
|
||||||
size_t pitch;
|
size_t pitch;
|
||||||
|
int id;
|
||||||
|
std::set<unsigned int>* cheapRectangles;
|
||||||
} RenderBackend_Surface;
|
} RenderBackend_Surface;
|
||||||
|
|
||||||
typedef struct RenderBackend_GlyphAtlas
|
typedef struct RenderBackend_GlyphAtlas
|
||||||
|
@ -86,12 +92,16 @@ RenderBackend_Surface* RenderBackend_CreateSurface(size_t width, size_t height,
|
||||||
surface->width = width;
|
surface->width = width;
|
||||||
surface->height = height;
|
surface->height = height;
|
||||||
surface->pitch = width * 4;
|
surface->pitch = width * 4;
|
||||||
|
surface->id = surfaceCount;
|
||||||
|
surface->cheapRectangles = new std::set<unsigned int>;
|
||||||
|
surfaceCount += 1;
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderBackend_FreeSurface(RenderBackend_Surface *surface)
|
void RenderBackend_FreeSurface(RenderBackend_Surface *surface)
|
||||||
{
|
{
|
||||||
|
delete surface->cheapRectangles;
|
||||||
free(surface->pixels);
|
free(surface->pixels);
|
||||||
free(surface);
|
free(surface);
|
||||||
}
|
}
|
||||||
|
@ -108,29 +118,106 @@ void RenderBackend_RestoreSurface(RenderBackend_Surface *surface)
|
||||||
(void)surface;
|
(void)surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dumpSurface(RenderBackend_Surface* surface) {
|
||||||
|
char filename[64] = {0};
|
||||||
|
sprintf(filename, "s%02d.ppm", surface->id);
|
||||||
|
FILE* fp = fopen(filename, "w");
|
||||||
|
fprintf(fp, "P3\n%ld %ld\n255\n", surface->width, surface->height);
|
||||||
|
|
||||||
|
for(int y = 0; y < surface->height; y++) {
|
||||||
|
int lineidx = y * surface->pitch;
|
||||||
|
for(int x = 0; x < surface->width; x++) {
|
||||||
|
int pixidx = lineidx + (x * 4);
|
||||||
|
#ifdef LITTLE_ENDIAN
|
||||||
|
fprintf(fp, "%d %d %d\n",
|
||||||
|
surface->pixels[pixidx + 2],
|
||||||
|
surface->pixels[pixidx + 1],
|
||||||
|
surface->pixels[pixidx + 0]);
|
||||||
|
#else
|
||||||
|
// Don't bother dumping out surfaces on the Sun.
|
||||||
|
// Hacky as hell, I know, but this isn't a forever project.
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines whether a particular tile uses transparency (color keying).
|
||||||
|
static bool rectUsesColorKey(RenderBackend_Surface* surface, RenderBackend_Rect* rect) {
|
||||||
|
for(int line = rect->top; line < rect->bottom; line++) {
|
||||||
|
for(int column = rect->left; column < rect->right; column++) {
|
||||||
|
unsigned index = (line * surface->pitch) + (column * 4);
|
||||||
|
if(surface->pixels[index + 0] == 0 &&
|
||||||
|
surface->pixels[index + 1] == 0 &&
|
||||||
|
surface->pixels[index + 2] == 0 &&
|
||||||
|
surface->pixels[index + 3] == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Goes through the surface and determines which 16x16 tiles can be drawn
|
||||||
|
// without using color keying. Such tiles are "cheap".
|
||||||
|
static void computeCheapRects(RenderBackend_Surface* surface) {
|
||||||
|
int rcolumns = surface->width / 16;
|
||||||
|
int rlines = surface->height / 16;
|
||||||
|
|
||||||
|
for(unsigned int ry = 0; ry < rlines; ry++) {
|
||||||
|
for(unsigned int rx = 0; rx < rcolumns; rx++) {
|
||||||
|
unsigned int px = rx * 16;
|
||||||
|
unsigned int py = ry * 16;
|
||||||
|
RenderBackend_Rect rect = { .left = px, .top = py, .right = px + 16, .bottom = py + 16 };
|
||||||
|
if(rectUsesColorKey(surface, &rect) == false) {
|
||||||
|
unsigned int rectOrigin = (px << 16) | py;
|
||||||
|
surface->cheapRectangles->insert(rectOrigin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RenderBackend_UploadSurface(RenderBackend_Surface *surface, const unsigned char *pixels, size_t width, size_t height)
|
void RenderBackend_UploadSurface(RenderBackend_Surface *surface, const unsigned char *pixels, size_t width, size_t height)
|
||||||
{
|
{
|
||||||
|
surface->cheapRectangles->clear();
|
||||||
|
|
||||||
for (size_t y = 0; y < height; ++y) {
|
for (size_t y = 0; y < height; ++y) {
|
||||||
int srcl = y * width * 3;
|
int srcl = y * width * 3;
|
||||||
int dstl = y * surface->pitch;
|
int dstl = y * surface->pitch;
|
||||||
for (size_t x = 0; x < width; ++x) {
|
for (size_t x = 0; x < width; ++x) {
|
||||||
int srcr = x * 3;
|
int srcr = x * 3;
|
||||||
int dstr = x * 4;
|
int dstr = x * 4;
|
||||||
|
|
||||||
#ifdef LITTLE_ENDIAN
|
#ifdef LITTLE_ENDIAN
|
||||||
surface->pixels[dstl + dstr + 0] = pixels[srcl + srcr + 2];
|
surface->pixels[dstl + dstr + 0] = pixels[srcl + srcr + 2];
|
||||||
surface->pixels[dstl + dstr + 1] = pixels[srcl + srcr + 1];
|
surface->pixels[dstl + dstr + 1] = pixels[srcl + srcr + 1];
|
||||||
surface->pixels[dstl + dstr + 2] = pixels[srcl + srcr + 0];
|
surface->pixels[dstl + dstr + 2] = pixels[srcl + srcr + 0];
|
||||||
|
surface->pixels[dstl + dstr + 3] = 0;
|
||||||
#else
|
#else
|
||||||
|
surface->pixels[dstl + dstr + 0] = 0;
|
||||||
surface->pixels[dstl + dstr + 1] = pixels[srcl + srcr + 2];
|
surface->pixels[dstl + dstr + 1] = pixels[srcl + srcr + 2];
|
||||||
surface->pixels[dstl + dstr + 2] = pixels[srcl + srcr + 1];
|
surface->pixels[dstl + dstr + 2] = pixels[srcl + srcr + 1];
|
||||||
surface->pixels[dstl + dstr + 3] = pixels[srcl + srcr + 0];
|
surface->pixels[dstl + dstr + 3] = pixels[srcl + srcr + 0];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
computeCheapRects(surface);
|
||||||
|
|
||||||
|
#ifdef LITTLE_ENDIAN // HACK!! Only dump surfaces on a little endian machine, i.e. my dev machine.
|
||||||
|
dumpSurface(surface);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ATTRIBUTE_HOT void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key)
|
ATTRIBUTE_HOT void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key)
|
||||||
{
|
{
|
||||||
|
// If the empty tile is used, don't bother blitting.
|
||||||
|
if(source_surface->id == 20 && rect->left == 0 && rect->top == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RenderBackend_Rect rect_clamped;
|
RenderBackend_Rect rect_clamped;
|
||||||
|
|
||||||
rect_clamped.left = rect->left;
|
rect_clamped.left = rect->left;
|
||||||
|
@ -169,6 +256,13 @@ ATTRIBUTE_HOT void RenderBackend_Blit(RenderBackend_Surface *source_surface, con
|
||||||
if (rect_clamped.right - rect_clamped.left <= 0)
|
if (rect_clamped.right - rect_clamped.left <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// If we're using a 16x16 tile...
|
||||||
|
if(rect->bottom - rect->top == 16 || rect->right - rect->left == 16) {
|
||||||
|
// ...enable color key only if this rectangle isn't a known cheap one.
|
||||||
|
// This way we don't need colorkeying for tiles that aren't transparent
|
||||||
|
colour_key = (source_surface->cheapRectangles->count((rect->left << 16) | rect->top) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Do the actual blitting
|
// Do the actual blitting
|
||||||
if (colour_key)
|
if (colour_key)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue