From e4437a278fa200aee01330e9b4b7992d1a6af01d Mon Sep 17 00:00:00 2001 From: FunkyFr3sh Date: Sat, 17 Nov 2018 05:54:22 +0100 Subject: [PATCH] Linear scaling using integer math (copied from ts-ddraw) --- cnc-ddraw.vcxproj | 1 + cnc-ddraw.vcxproj.filters | 3 + inc/scale_pattern.h | 18 +++++ src/surface.c | 139 +++++++++++++++++++++++++++++++++++++- 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 inc/scale_pattern.h diff --git a/cnc-ddraw.vcxproj b/cnc-ddraw.vcxproj index 79127ec..8cf55cb 100644 --- a/cnc-ddraw.vcxproj +++ b/cnc-ddraw.vcxproj @@ -38,6 +38,7 @@ + diff --git a/cnc-ddraw.vcxproj.filters b/cnc-ddraw.vcxproj.filters index 13536df..1819585 100644 --- a/cnc-ddraw.vcxproj.filters +++ b/cnc-ddraw.vcxproj.filters @@ -95,6 +95,9 @@ Header Files + + Header Files + diff --git a/inc/scale_pattern.h b/inc/scale_pattern.h new file mode 100644 index 0000000..a4027df --- /dev/null +++ b/inc/scale_pattern.h @@ -0,0 +1,18 @@ +#ifndef _SCALE_PATTERN_H +#define _SCALE_PATTERN_H + +typedef enum { + REPEAT, + SEQUENCE, + ONCE, + END +} SCALE_PATTERN_TYPE; + +typedef struct { + SCALE_PATTERN_TYPE type; + int dst_index; + int src_index; + int count; +} scale_pattern; + +#endif diff --git a/src/surface.c b/src/surface.c index c66637a..4926f30 100644 --- a/src/surface.c +++ b/src/surface.c @@ -19,6 +19,7 @@ #include "main.h" #include "surface.h" +#include "scale_pattern.h" void dump_ddbltflags(DWORD dwFlags); void dump_ddscaps(DWORD dwCaps); @@ -244,7 +245,143 @@ HRESULT __stdcall ddraw_surface_Blt(IDirectDrawSurfaceImpl *This, LPRECT lpDestR } } else - StretchBlt(This->hDC, dst_x, dst_y, dst_w, dst_h, Source->hDC, src_x, src_y, src_w, src_h, SRCCOPY); + { + /* Linear scaling using integer math + * Since the scaling pattern for x will aways be the same, the pattern itself gets pre-calculated + * and stored in an array. + * Y scaling pattern gets calculated during the blit loop + */ + unsigned int x_ratio = (unsigned int)((src_w << 16) / dst_w) + 1; + unsigned int y_ratio = (unsigned int)((src_h << 16) / dst_h) + 1; + + unsigned int s_src_x, s_src_y; + unsigned int dest_base, source_base; + + scale_pattern *pattern = malloc((dst_w + 1) * (sizeof(scale_pattern))); + int pattern_idx = 0; + unsigned int last_src_x = 0; + + if (pattern != NULL) + { + pattern[pattern_idx] = (scale_pattern) { ONCE, 0, 0, 1 }; + + /* Build the pattern! */ + for (int x = 1; x < dst_w; x++) { + s_src_x = (x * x_ratio) >> 16; + if (s_src_x == last_src_x) + { + if (pattern[pattern_idx].type == REPEAT || pattern[pattern_idx].type == ONCE) + { + pattern[pattern_idx].type = REPEAT; + pattern[pattern_idx].count++; + } + else if (pattern[pattern_idx].type == SEQUENCE) + { + pattern_idx++; + pattern[pattern_idx] = (scale_pattern) { REPEAT, x, s_src_x, 1 }; + } + } + else if (s_src_x == last_src_x + 1) + { + if (pattern[pattern_idx].type == SEQUENCE || pattern[pattern_idx].type == ONCE) + { + pattern[pattern_idx].type = SEQUENCE; + pattern[pattern_idx].count++; + } + else if (pattern[pattern_idx].type == REPEAT) + { + pattern_idx++; + pattern[pattern_idx] = (scale_pattern) { ONCE, x, s_src_x, 1 }; + } + } + else + { + pattern_idx++; + pattern[pattern_idx] = (scale_pattern) { ONCE, x, s_src_x, 1 }; + } + last_src_x = s_src_x; + } + pattern[pattern_idx + 1] = (scale_pattern) { END, 0, 0, 0 }; + + + /* Do the actual blitting */ + void *d, *s; + int count = 0; + + for (int y = 0; y < dst_h; y++) { + + dest_base = dst_x + This->width * (y + dst_y); + + s_src_y = (y * y_ratio) >> 16; + + source_base = src_x + Source->width * (s_src_y + src_y); + + pattern_idx = 0; + scale_pattern *current = &pattern[pattern_idx]; + do { + switch (current->type) + { + case ONCE: + if (This->bpp == 8) + { + ((unsigned char *)This->surface)[dest_base + current->dst_index] = + ((unsigned char *)Source->surface)[source_base + current->src_index]; + } + else if (This->bpp == 16) + { + ((unsigned short *)This->surface)[dest_base + current->dst_index] = + ((unsigned short *)Source->surface)[source_base + current->src_index]; + } + break; + + case REPEAT: + if (This->bpp == 8) + { + d = ((unsigned char *)This->surface + dest_base + current->dst_index); + unsigned char v = ((unsigned char *)Source->surface)[source_base + current->src_index]; + + count = current->count; + while (count-- > 0) + *((unsigned char *)d)++ = v; + } + else if (This->bpp == 16) + { + d = ((unsigned short *)This->surface + dest_base + current->dst_index); + unsigned short v = ((unsigned short *)Source->surface)[source_base + current->src_index]; + + count = current->count; + while (count-- > 0) + *((unsigned short *)d)++ = v; + } + + break; + + case SEQUENCE: + if (This->bpp == 8) + { + d = ((unsigned char *)This->surface) + dest_base + current->dst_index; + s = ((unsigned char *)Source->surface) + source_base + current->src_index; + } + else if (This->bpp == 16) + { + d = ((unsigned short *)This->surface) + dest_base + current->dst_index; + s = ((unsigned short *)Source->surface) + source_base + current->src_index; + } + + memcpy(d, s, current->count * This->lXPitch); + break; + + case END: + default: + break; + } + + current = &pattern[++pattern_idx]; + } while (current->type != END); + } + free(pattern); + } + } } }