mirror of https://github.com/OpenRCT2/OpenRCT2.git
fix water rendering
This commit is contained in:
parent
c9b5ec4172
commit
c301e83a64
|
@ -21,11 +21,6 @@ extern "C"
|
|||
#include "drawing.h"
|
||||
}
|
||||
|
||||
// This will have -1 (0xffffffff) for (val <= 0), 0 otherwise, so it can act as a mask
|
||||
// This is expected to generate
|
||||
// sar eax, 0x1f (arithmetic shift right by 31)
|
||||
#define less_or_equal_zero_mask(val) (((val - 1) >> (sizeof(val) * 8 - 1)))
|
||||
|
||||
template<sint32 image_type, sint32 zoom_level>
|
||||
static void FASTCALL DrawRLESprite2(const uint8* RESTRICT source_bits_pointer,
|
||||
uint8* RESTRICT dest_bits_pointer,
|
||||
|
@ -36,104 +31,119 @@ static void FASTCALL DrawRLESprite2(const uint8* RESTRICT source_bits_pointer,
|
|||
sint32 source_x_start,
|
||||
sint32 width)
|
||||
{
|
||||
// The distance between two samples in the source image.
|
||||
// We draw the image at 1 / (2^zoom_level) scale.
|
||||
sint32 zoom_amount = 1 << zoom_level;
|
||||
sint32 zoom_mask = 0xFFFFFFFF << zoom_level;
|
||||
uint8* next_dest_pointer = dest_bits_pointer;
|
||||
|
||||
// Width of one screen line in the dest buffer
|
||||
sint32 line_width = (dpi->width >> zoom_level) + dpi->pitch;
|
||||
|
||||
const sint32 source_y_start_mask = less_or_equal_zero_mask(source_y_start + 1);
|
||||
source_y_start += zoom_amount & source_y_start_mask;
|
||||
next_dest_pointer += line_width & source_y_start_mask;
|
||||
height -= zoom_amount & source_y_start_mask;
|
||||
// Move up to the first line of the image if source_y_start is negative. Why does this even occur?
|
||||
if (source_y_start < 0)
|
||||
{
|
||||
source_y_start += zoom_amount;
|
||||
height -= zoom_amount;
|
||||
dest_bits_pointer += line_width;
|
||||
}
|
||||
|
||||
// For every line in the image
|
||||
for (sint32 i = 0; i < height; i += zoom_amount) {
|
||||
//For every line in the image
|
||||
for (sint32 i = 0; i < height; i += zoom_amount)
|
||||
{
|
||||
sint32 y = source_y_start + i;
|
||||
uint8 i2 = i >> zoom_level;
|
||||
|
||||
// The first part of the source pointer is a list of offsets to different lines
|
||||
// This will move the pointer to the correct source line.
|
||||
const uint8 *next_source_pointer = source_bits_pointer + ((uint16*)source_bits_pointer)[y];
|
||||
uint8* loop_dest_pointer = next_dest_pointer + line_width * i2;
|
||||
//The first part of the source pointer is a list of offsets to different lines
|
||||
//This will move the pointer to the correct source line.
|
||||
const uint8 *lineData = source_bits_pointer + ((uint16*)source_bits_pointer)[y];
|
||||
uint8* loop_dest_pointer = dest_bits_pointer + line_width * (i >> zoom_level);
|
||||
|
||||
uint8 last_data_line = 0;
|
||||
uint8 isEndOfLine = 0;
|
||||
|
||||
// For every data section in the line
|
||||
while (!last_data_line) {
|
||||
const uint8* source_pointer = next_source_pointer;
|
||||
uint8* dest_pointer = loop_dest_pointer;
|
||||
// For every data chunk in the line
|
||||
while (!isEndOfLine)
|
||||
{
|
||||
const uint8* copySrc = lineData;
|
||||
//uint8* copyDest = loop_dest_pointer;
|
||||
|
||||
sint32 no_pixels = *source_pointer++;
|
||||
// gap_size is the number of non drawn pixels you require to
|
||||
// jump over on your destination
|
||||
uint8 gap_size = *source_pointer++;
|
||||
// The last bit in no_pixels tells you if you have reached the end of a line
|
||||
last_data_line = no_pixels & 0x80;
|
||||
// Clear the last data line bit so we have just the no_pixels
|
||||
no_pixels &= 0x7f;
|
||||
// Have our next source pointer point to the next data section
|
||||
next_source_pointer = source_pointer + no_pixels;
|
||||
// Read chunk metadata
|
||||
uint8 dataSize = *copySrc++;
|
||||
uint8 firstPixelX = *copySrc++;
|
||||
|
||||
// Calculates the start point of the image
|
||||
sint32 x_start = gap_size - source_x_start;
|
||||
const sint32 x_diff = x_start & ~zoom_mask;
|
||||
const sint32 x_mask = ~less_or_equal_zero_mask(x_diff);
|
||||
isEndOfLine = dataSize & 0x80; // If the last bit in dataSize is set, then this is the last line
|
||||
dataSize &= 0x7F; // The rest of the bits are the actual size
|
||||
|
||||
no_pixels -= x_diff;
|
||||
x_start += ~zoom_mask & x_mask;
|
||||
source_pointer += (x_start&~zoom_mask) & x_mask;
|
||||
//Have our next source pointer point to the next data section
|
||||
lineData = copySrc + dataSize;
|
||||
|
||||
// This will have -1 (0xffffffff) for (x_start <= 0), 0 otherwise
|
||||
sint32 sign = less_or_equal_zero_mask(x_start);
|
||||
sint32 x_start = firstPixelX - source_x_start;
|
||||
sint32 numPixels = dataSize;
|
||||
|
||||
dest_pointer += (x_start >> zoom_level) & ~sign;
|
||||
|
||||
// If the start is negative we require to remove part of the image.
|
||||
// This is done by moving the image pointer to the correct position.
|
||||
source_pointer -= x_start & sign;
|
||||
// The no_pixels will be reduced in this operation
|
||||
no_pixels += x_start & sign;
|
||||
// Reset the start position to zero as we have taken into account all moves
|
||||
x_start &= ~sign;
|
||||
|
||||
sint32 x_end = x_start + no_pixels;
|
||||
// If the end position is further out than the whole image
|
||||
// end position then we need to shorten the line again
|
||||
const sint32 pixels_till_end = x_end - width;
|
||||
// Shorten the line
|
||||
no_pixels -= pixels_till_end & ~(less_or_equal_zero_mask(pixels_till_end));
|
||||
|
||||
// Finally after all those checks, copy the image onto the drawing surface
|
||||
// If the image type is not a basic one we require to mix the pixels
|
||||
if (image_type & IMAGE_TYPE_REMAP) {//In the .exe these are all unraveled loops
|
||||
for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++) {
|
||||
uint8 al = *source_pointer;
|
||||
uint8 ah = *dest_pointer;
|
||||
if (image_type & IMAGE_TYPE_TRANSPARENT)
|
||||
al = palette_pointer[(((uint16)al << 8) | ah) - 0x100];
|
||||
else
|
||||
al = palette_pointer[al];
|
||||
*dest_pointer = al;
|
||||
}
|
||||
} else if (image_type & IMAGE_TYPE_TRANSPARENT) {//In the .exe these are all unraveled loops
|
||||
// Doesn't use source pointer ??? mix with background only?
|
||||
// Not Tested
|
||||
|
||||
for (; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++) {
|
||||
uint8 pixel = *dest_pointer;
|
||||
pixel = palette_pointer[pixel];
|
||||
*dest_pointer = pixel;
|
||||
}
|
||||
} else
|
||||
if (x_start > 0)
|
||||
{
|
||||
if (zoom_amount == 1) {
|
||||
no_pixels &= ~less_or_equal_zero_mask(no_pixels);
|
||||
memcpy(dest_pointer, source_pointer, no_pixels);
|
||||
} else {
|
||||
for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++) {
|
||||
*dest_pointer = *source_pointer;
|
||||
int mod = x_start & (zoom_amount - 1); // x_start modulo zoom_amount
|
||||
|
||||
// If x_start is not a multiple of zoom_amount, round it up to a multiple
|
||||
if (mod != 0)
|
||||
{
|
||||
int offset = zoom_amount - mod;
|
||||
x_start += offset;
|
||||
copySrc += offset;
|
||||
numPixels -= offset;
|
||||
}
|
||||
}
|
||||
else if (x_start < 0)
|
||||
{
|
||||
// Clamp x_start to zero if negative
|
||||
int offset = 0 - x_start;
|
||||
x_start = 0;
|
||||
copySrc += offset;
|
||||
numPixels -= offset;
|
||||
}
|
||||
|
||||
//If the end position is further out than the whole image
|
||||
//end position then we need to shorten the line again
|
||||
if (x_start + numPixels > width)
|
||||
numPixels = width - x_start;
|
||||
|
||||
uint8 *copyDest = loop_dest_pointer + (x_start >> zoom_level);
|
||||
|
||||
//Finally after all those checks, copy the image onto the drawing surface
|
||||
//If the image type is not a basic one we require to mix the pixels
|
||||
if (image_type & IMAGE_TYPE_REMAP) // palette controlled images
|
||||
{
|
||||
for (int j = 0; j < numPixels; j += zoom_amount, copySrc += zoom_amount, copyDest++)
|
||||
{
|
||||
if (image_type & IMAGE_TYPE_TRANSPARENT)
|
||||
{
|
||||
uint16 color = ((*copySrc << 8) | *copyDest) - 0x100;
|
||||
*copyDest = palette_pointer[color];
|
||||
}
|
||||
else
|
||||
{
|
||||
*copyDest = palette_pointer[*copySrc];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (image_type & IMAGE_TYPE_TRANSPARENT) // single alpha blended color (used for glass)
|
||||
{
|
||||
for (int j = 0; j < numPixels; j += zoom_amount, copyDest++)
|
||||
{
|
||||
uint8 pixel = *copyDest;
|
||||
pixel = palette_pointer[pixel];
|
||||
*copyDest = pixel;
|
||||
}
|
||||
}
|
||||
else // standard opaque image
|
||||
{
|
||||
if (zoom_level == 0)
|
||||
{
|
||||
// Since we're sampling each pixel at this zoom level, just do a straight memcpy
|
||||
if (numPixels > 0)
|
||||
memcpy(copyDest, copySrc, numPixels);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < numPixels; j += zoom_amount, copySrc += zoom_amount, copyDest++)
|
||||
*copyDest = *copySrc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue