blob: 01d6174741363701107e50dfe1a9e5266a7c1c72 [file] [log] [blame]
#!/usr/bin/perl -w
#
# A script to generate optimized C blitters for Simple DirectMedia Layer
# http://www.libsdl.org/
use warnings;
use strict;
my %file;
# The formats potentially supported by this script:
# SDL_PIXELFORMAT_INDEX8
# SDL_PIXELFORMAT_RGB332
# SDL_PIXELFORMAT_RGB444
# SDL_PIXELFORMAT_RGB555
# SDL_PIXELFORMAT_ARGB4444
# SDL_PIXELFORMAT_ARGB1555
# SDL_PIXELFORMAT_RGB565
# SDL_PIXELFORMAT_RGB24
# SDL_PIXELFORMAT_BGR24
# SDL_PIXELFORMAT_RGB888
# SDL_PIXELFORMAT_BGR888
# SDL_PIXELFORMAT_ARGB8888
# SDL_PIXELFORMAT_RGBA8888
# SDL_PIXELFORMAT_ABGR8888
# SDL_PIXELFORMAT_BGRA8888
# SDL_PIXELFORMAT_ARGB2101010
# The formats we're actually creating blitters for:
my @src_formats = (
"RGB888",
"BGR888",
"ARGB8888",
"RGBA8888",
"ABGR8888",
"BGRA8888",
);
my @dst_formats = (
"RGB888",
"BGR888",
);
my %format_size = (
"RGB888" => 4,
"BGR888" => 4,
"ARGB8888" => 4,
"RGBA8888" => 4,
"ABGR8888" => 4,
"BGRA8888" => 4,
);
my %format_type = (
"RGB888" => "Uint32",
"BGR888" => "Uint32",
"ARGB8888" => "Uint32",
"RGBA8888" => "Uint32",
"ABGR8888" => "Uint32",
"BGRA8888" => "Uint32",
);
my %get_rgba_string = (
"RGB888" => "_R = (Uint8)(_pixel >> 16); _G = (Uint8)(_pixel >> 8); _B = (Uint8)_pixel; _A = 0xFF;",
"BGR888" => "_B = (Uint8)(_pixel >> 16); _G = (Uint8)(_pixel >> 8); _R = (Uint8)_pixel; _A = 0xFF;",
"ARGB8888" => "_A = (Uint8)(_pixel >> 24); _R = (Uint8)(_pixel >> 16); _G = (Uint8)(_pixel >> 8); _B = (Uint8)_pixel;",
"RGBA8888" => "_R = (Uint8)(_pixel >> 24); _G = (Uint8)(_pixel >> 16); _B = (Uint8)(_pixel >> 8); _A = (Uint8)_pixel;",
"ABGR8888" => "_A = (Uint8)(_pixel >> 24); _B = (Uint8)(_pixel >> 16); _G = (Uint8)(_pixel >> 8); _R = (Uint8)_pixel;",
"BGRA8888" => "_B = (Uint8)(_pixel >> 24); _G = (Uint8)(_pixel >> 16); _R = (Uint8)(_pixel >> 8); _A = (Uint8)_pixel;",
);
my %set_rgba_string = (
"RGB888" => "_pixel = ((Uint32)_R << 16) | ((Uint32)_G << 8) | _B;",
"BGR888" => "_pixel = ((Uint32)_B << 16) | ((Uint32)_G << 8) | _R;",
);
sub open_file {
my $name = shift;
open(FILE, ">$name.new") || die "Cant' open $name.new: $!";
print FILE <<__EOF__;
/* DO NOT EDIT! This file is generated by sdlgenblit.pl */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken\@libsdl.org
*/
#include "SDL_config.h"
/* *INDENT-OFF* */
__EOF__
}
sub close_file {
my $name = shift;
print FILE <<__EOF__;
/* *INDENT-ON* */
/* vi: set ts=4 sw=4 expandtab: */
__EOF__
close FILE;
if ( ! -f $name || system("cmp -s $name $name.new") != 0 ) {
rename("$name.new", "$name");
} else {
unlink("$name.new");
}
}
sub output_copydefs
{
print FILE <<__EOF__;
#define SDL_RENDERCOPY_MODULATE_COLOR 0x0001
#define SDL_RENDERCOPY_MODULATE_ALPHA 0x0002
#define SDL_RENDERCOPY_MASK 0x0010
#define SDL_RENDERCOPY_BLEND 0x0020
#define SDL_RENDERCOPY_ADD 0x0040
#define SDL_RENDERCOPY_MOD 0x0080
#define SDL_RENDERCOPY_NEAREST 0x0100
typedef struct {
void *src;
int src_w, src_h;
int src_pitch;
void *dst;
int dst_w, dst_h;
int dst_pitch;
void *aux_data;
int flags;
Uint8 r, g, b, a;
} SDL_RenderCopyData;
typedef int (*SDL_RenderCopyFunc)(SDL_RenderCopyData *data);
extern SDL_RenderCopyFunc SDLCALL SDL_GetRenderCopyFunc(Uint32 src_format, Uint32 dst_format, int modMode, int blendMode, int scaleMode);
__EOF__
}
sub output_copyfuncname
{
my $prefix = shift;
my $src = shift;
my $dst = shift;
my $modulate = shift;
my $blend = shift;
my $scale = shift;
my $args = shift;
my $suffix = shift;
print FILE "$prefix SDL_RenderCopy_${src}_${dst}";
if ( $modulate ) {
print FILE "_Modulate";
}
if ( $blend ) {
print FILE "_Blend";
}
if ( $scale ) {
print FILE "_Scale";
}
if ( $args ) {
print FILE "(SDL_RenderCopyData *data)";
}
print FILE "$suffix";
}
sub get_rgba
{
my $prefix = shift;
my $format = shift;
my $string = $get_rgba_string{$format};
$string =~ s/_/$prefix/g;
if ( $prefix ne "" ) {
print FILE <<__EOF__;
${prefix}pixel = *$prefix;
__EOF__
} else {
print FILE <<__EOF__;
pixel = *src;
__EOF__
}
print FILE <<__EOF__;
$string
__EOF__
}
sub set_rgba
{
my $prefix = shift;
my $format = shift;
my $string = $set_rgba_string{$format};
$string =~ s/_/$prefix/g;
print FILE <<__EOF__;
$string
*dst = ${prefix}pixel;
__EOF__
}
sub output_copycore
{
my $src = shift;
my $dst = shift;
my $modulate = shift;
my $blend = shift;
my $s = "";
my $d = "";
# Nice and easy...
if ( $src eq $dst && !$modulate && !$blend ) {
print FILE <<__EOF__;
*dst = *src;
__EOF__
return;
}
if ( $blend ) {
get_rgba("src", $src);
get_rgba("dst", $dst);
$s = "src";
$d = "dst";
} else {
get_rgba("", $src);
}
if ( $modulate ) {
print FILE <<__EOF__;
if (flags & SDL_RENDERCOPY_MODULATE_COLOR) {
${s}R = (${s}R * modulateR) / 255;
${s}G = (${s}G * modulateG) / 255;
${s}B = (${s}B * modulateB) / 255;
}
if (flags & SDL_RENDERCOPY_MODULATE_ALPHA) {
${s}A = (${s}A * modulateA) / 255;
}
__EOF__
}
if ( $blend ) {
print FILE <<__EOF__;
if (flags & (SDL_RENDERCOPY_BLEND|SDL_RENDERCOPY_ADD)) {
/* This goes away if we ever use premultiplied alpha */
if (${s}A < 255) {
${s}R = (${s}R * ${s}A) / 255;
${s}G = (${s}G * ${s}A) / 255;
${s}B = (${s}B * ${s}A) / 255;
}
}
switch (flags & (SDL_RENDERCOPY_MASK|SDL_RENDERCOPY_BLEND|SDL_RENDERCOPY_ADD|SDL_RENDERCOPY_MOD)) {
case SDL_RENDERCOPY_MASK:
if (${s}A) {
${d}R = ${s}R;
${d}G = ${s}G;
${d}B = ${s}B;
}
break;
case SDL_RENDERCOPY_BLEND:
${d}R = ${s}R + ((255 - ${s}A) * ${d}R) / 255;
${d}G = ${s}G + ((255 - ${s}A) * ${d}G) / 255;
${d}B = ${s}B + ((255 - ${s}A) * ${d}B) / 255;
break;
case SDL_RENDERCOPY_ADD:
${d}R = ${s}R + ${d}R; if (${d}R > 255) ${d}R = 255;
${d}G = ${s}G + ${d}G; if (${d}G > 255) ${d}G = 255;
${d}B = ${s}B + ${d}B; if (${d}B > 255) ${d}B = 255;
break;
case SDL_RENDERCOPY_MOD:
${d}R = (${s}R * ${d}R) / 255;
${d}G = (${s}G * ${d}G) / 255;
${d}B = (${s}B * ${d}B) / 255;
break;
}
__EOF__
}
if ( $blend ) {
set_rgba("dst", $dst);
} else {
set_rgba("", $dst);
}
}
sub output_copyfunc
{
my $src = shift;
my $dst = shift;
my $modulate = shift;
my $blend = shift;
my $scale = shift;
output_copyfuncname("int", $src, $dst, $modulate, $blend, $scale, 1, "\n");
print FILE <<__EOF__;
{
const int flags = data->flags;
__EOF__
if ( $modulate ) {
print FILE <<__EOF__;
const Uint32 modulateR = data->r;
const Uint32 modulateG = data->g;
const Uint32 modulateB = data->b;
const Uint32 modulateA = data->a;
__EOF__
}
if ( $blend ) {
print FILE <<__EOF__;
Uint32 srcpixel;
Uint32 srcR, srcG, srcB, srcA;
Uint32 dstpixel;
Uint32 dstR, dstG, dstB, dstA;
__EOF__
} elsif ( $modulate || $src ne $dst ) {
print FILE <<__EOF__;
Uint32 pixel;
Uint32 R, G, B, A;
__EOF__
}
if ( $scale ) {
print FILE <<__EOF__;
int srcy, srcx;
int posy, posx;
int incy, incx;
srcy = 0;
posy = 0;
incy = (data->src_h << 16) / data->dst_h;
incx = (data->src_w << 16) / data->dst_w;
while (data->dst_h--) {
$format_type{$src} *src;
$format_type{$dst} *dst = ($format_type{$dst} *)data->dst;
int n = data->dst_w;
srcx = -1;
posx = 0x10000L;
while (posy >= 0x10000L) {
++srcy;
posy -= 0x10000L;
}
while (n--) {
if (posx >= 0x10000L) {
while (posx >= 0x10000L) {
++srcx;
posx -= 0x10000L;
}
src = ($format_type{$src} *)(data->src + (srcy * data->src_pitch) + (srcx * $format_size{$src}));
__EOF__
print FILE <<__EOF__;
}
__EOF__
output_copycore($src, $dst, $modulate, $blend);
print FILE <<__EOF__;
posx += incx;
++dst;
}
posy += incy;
data->dst += data->dst_pitch;
}
__EOF__
} else {
print FILE <<__EOF__;
while (data->dst_h--) {
$format_type{$src} *src = ($format_type{$src} *)data->src;
$format_type{$dst} *dst = ($format_type{$dst} *)data->dst;
int n = data->dst_w;
while (n--) {
__EOF__
output_copycore($src, $dst, $modulate, $blend);
print FILE <<__EOF__;
++src;
++dst;
}
data->src += data->src_pitch;
data->dst += data->dst_pitch;
}
__EOF__
}
print FILE <<__EOF__;
return 0;
}
__EOF__
}
sub output_copyfunc_h
{
my $src = shift;
my $dst = shift;
for (my $modulate = 0; $modulate <= 1; ++$modulate) {
for (my $blend = 0; $blend <= 1; ++$blend) {
for (my $scale = 0; $scale <= 1; ++$scale) {
if ( $modulate || $blend || $scale ) {
output_copyfuncname("extern int SDLCALL", $src, $dst, $modulate, $blend, $scale, 1, ";\n");
}
}
}
}
}
sub output_copyinc
{
print FILE <<__EOF__;
#include "SDL_video.h"
#include "SDL_rendercopy.h"
__EOF__
}
sub output_copyfunctable
{
print FILE <<__EOF__;
static struct {
Uint32 src_format;
Uint32 dst_format;
int modMode;
int blendMode;
int scaleMode;
SDL_RenderCopyFunc func;
} SDL_RenderCopyFuncTable[] = {
__EOF__
for (my $i = 0; $i <= $#src_formats; ++$i) {
my $src = $src_formats[$i];
for (my $j = 0; $j <= $#dst_formats; ++$j) {
my $dst = $dst_formats[$j];
for (my $modulate = 0; $modulate <= 1; ++$modulate) {
for (my $blend = 0; $blend <= 1; ++$blend) {
for (my $scale = 0; $scale <= 1; ++$scale) {
if ( $modulate || $blend || $scale ) {
print FILE " { SDL_PIXELFORMAT_$src, SDL_PIXELFORMAT_$dst, ";
if ( $modulate ) {
print FILE "(SDL_TEXTUREMODULATE_COLOR | SDL_TEXTUREMODULATE_ALPHA), ";
} else {
print FILE "0, ";
}
if ( $blend ) {
print FILE "(SDL_TEXTUREBLENDMODE_MASK | SDL_TEXTUREBLENDMODE_BLEND | SDL_TEXTUREBLENDMODE_ADD | SDL_TEXTUREBLENDMODE_MOD), ";
} else {
print FILE "0, ";
}
if ( $scale ) {
print FILE "SDL_TEXTURESCALEMODE_FAST, ";
} else {
print FILE "0, ";
}
output_copyfuncname("", $src_formats[$i], $dst_formats[$j], $modulate, $blend, $scale, 0, " },\n");
}
}
}
}
}
}
print FILE <<__EOF__;
};
SDL_RenderCopyFunc SDL_GetRenderCopyFunc(Uint32 src_format, Uint32 dst_format, int modMode, int blendMode, int scaleMode)
{
int i;
for (i = 0; i < SDL_arraysize(SDL_RenderCopyFuncTable); ++i) {
if (src_format != SDL_RenderCopyFuncTable[i].src_format) {
continue;
}
if (dst_format != SDL_RenderCopyFuncTable[i].dst_format) {
continue;
}
if ((modMode & SDL_RenderCopyFuncTable[i].modMode) != modMode) {
continue;
}
if ((blendMode & SDL_RenderCopyFuncTable[i].blendMode) != blendMode) {
continue;
}
if ((scaleMode & SDL_RenderCopyFuncTable[i].scaleMode) != scaleMode) {
continue;
}
return SDL_RenderCopyFuncTable[i].func;
}
return NULL;
}
__EOF__
}
sub output_copyfunc_c
{
my $src = shift;
my $dst = shift;
for (my $modulate = 0; $modulate <= 1; ++$modulate) {
for (my $blend = 0; $blend <= 1; ++$blend) {
for (my $scale = 0; $scale <= 1; ++$scale) {
if ( $modulate || $blend || $scale ) {
output_copyfunc($src, $dst, $modulate, $blend, $scale);
}
}
}
}
}
open_file("SDL_rendercopy.h");
output_copydefs();
for (my $i = 0; $i <= $#src_formats; ++$i) {
for (my $j = 0; $j <= $#dst_formats; ++$j) {
output_copyfunc_h($src_formats[$i], $dst_formats[$j]);
}
}
print FILE "\n";
close_file("SDL_rendercopy.h");
open_file("SDL_rendercopy.c");
output_copyinc();
output_copyfunctable();
for (my $i = 0; $i <= $#src_formats; ++$i) {
for (my $j = 0; $j <= $#dst_formats; ++$j) {
output_copyfunc_c($src_formats[$i], $dst_formats[$j]);
}
}
close_file("SDL_rendercopy.c");