From ed81691dd5f56f89d4b431fb08f75c3df42351d2 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Fri, 28 Aug 2026 15:36:22 +0200 Subject: [PATCH 01/14] Translate voxel drawing and colour operations to C++ No documentation update: tests/colorops and tests/voxeldraw check the C++ port against golden vectors recorded from the original assembly, so documented behavior is unchanged. --- code/colorops.cpp | 349 +++++++++++++++++++++++++++ code/interpal.cpp | 412 -------------------------------- code/interpal.h | 30 --- code/voxlib.cpp | 58 ++--- tests/CMakeLists.txt | 3 +- tests/colorops/CMakeLists.txt | 30 +++ tests/colorops/colorgolden.h | 126 ++++++++++ tests/colorops/coloropstest.cpp | 173 ++++++++++++++ tests/voxeldraw/CMakeLists.txt | 30 +++ tests/voxeldraw/voxeldraw.cpp | 232 ++++++++++++++++++ tests/voxeldraw/voxelgolden.h | 171 +++++++++++++ 11 files changed, 1137 insertions(+), 477 deletions(-) create mode 100644 code/colorops.cpp delete mode 100644 code/interpal.cpp delete mode 100644 code/interpal.h create mode 100644 tests/colorops/CMakeLists.txt create mode 100644 tests/colorops/colorgolden.h create mode 100644 tests/colorops/coloropstest.cpp create mode 100644 tests/voxeldraw/CMakeLists.txt create mode 100644 tests/voxeldraw/voxeldraw.cpp create mode 100644 tests/voxeldraw/voxelgolden.h diff --git a/code/colorops.cpp b/code/colorops.cpp new file mode 100644 index 00000000..c1648281 --- /dev/null +++ b/code/colorops.cpp @@ -0,0 +1,349 @@ +/******************************************************************************* + * O P E N T S + ******************************************************************************* + * SPDX-License-Identifier: GPL-3.0-or-later + * Copyright 2025 Electronic Arts Inc. + * Copyright 2026 OpenTS contributors + * + * Contains material derived from Electronic Arts source code. + * Modified by OpenTS contributors, 2026. + * EA's GPLv3 Section 7 additional terms and supplemental warranty + * disclaimers apply; see LICENSE.md. + ******************************************************************************/ + +/**************************************************************************** +* +* File : winasm.asm +* Description : Palette tinting and spot light brightening for each of +* the supported hicolor pixel layouts. +* +****************************************************************************/ + +#include "always.h" + +/* + * Two families of routine, each replacing four assembly routines of the same names, one per + * hicolor layout. + * + * Adjust_Color_* builds a palette translation table: every colour is scaled and packed into a + * pixel. A colour whose mask entry is set is scaled by the separate red, green and blue tints; + * one whose entry is clear is scaled by the single intensity instead. + * + * Brighten_Color_* and MMX_Brighten_Color_* lighten a hicolor image through a per-pixel + * multiplier. The two reach the same shape by different routes -- the first unpacks each pixel + * with shifts, the second reads the channels out of a caller-supplied 65536 entry table -- and + * they are kept apart here rather than folded together, because only the caller knows whether + * the table it built agrees with the shifts. + * + * The assembly had three hand-written paths through Adjust_Color, chosen at run time by the + * MMX and CMOV flags. All three computed the same thing, so one routine replaces them. + */ + +namespace { + +/* + * How one hicolor layout packs a colour. The mask keeps the bits a channel is allowed to + * carry, and the shift moves them into place; red and green shift up, blue shifts down. + */ +struct PackFormat { + unsigned int RedMask; + unsigned int RedShift; + unsigned int GreenMask; + unsigned int GreenShift; + unsigned int BlueMask; + unsigned int BlueShift; +}; + +PackFormat const _Format565 = {0xF8, 8, 0xFC, 3, 0xF8, 3}; +PackFormat const _Format555 = {0xF8, 7, 0xF8, 2, 0xF8, 3}; +PackFormat const _Format556 = {0xF8, 8, 0xF8, 3, 0xFC, 2}; +PackFormat const _Format655 = {0xFC, 8, 0xF8, 2, 0xF8, 3}; + + +/// +/// Scales one channel by a fixed point factor and holds the result at 255. The assembly built +/// the ceiling out of the carry flag; the multiply wraps at 32 bits either way. +/// +/// The channel value, 0 to 255. +/// The 16.16 fixed point factor to scale it by. +/// unsigned int; The scaled channel, at most 255. +inline unsigned int Scale_Channel(unsigned int channel, unsigned int scale) +{ + unsigned int const scaled = (unsigned int)(channel * scale) >> 16; + return((scaled > 255) ? 255 : scaled); +} + + +void Adjust_Color(unsigned char const * palette, unsigned short * translator, int red, int green, int blue, + int intensity, unsigned char const * mask, PackFormat const & format) +{ + /* + * Index zero is the transparent one and is never scaled. + */ + translator[0] = 0; + + for (int i = 1; i < 256; i++) { + unsigned int const r = palette[i * 3 + 0]; + unsigned int const g = palette[i * 3 + 1]; + unsigned int const b = palette[i * 3 + 2]; + + unsigned int redscale = (unsigned int)intensity; + unsigned int greenscale = (unsigned int)intensity; + unsigned int bluescale = (unsigned int)intensity; + + if (mask[i] != 0) { + redscale = (unsigned int)red; + greenscale = (unsigned int)green; + bluescale = (unsigned int)blue; + } + + unsigned int const outr = Scale_Channel(r, redscale); + unsigned int const outg = Scale_Channel(g, greenscale); + unsigned int const outb = Scale_Channel(b, bluescale); + + translator[i] = (unsigned short)(((outr & format.RedMask) << format.RedShift) + | ((outg & format.GreenMask) << format.GreenShift) + | ((outb & format.BlueMask) >> format.BlueShift)); + } +} + + +/* + * How one layout is taken apart and put back together by the brightening routines. The names + * follow the order the assembly worked in rather than red, green, blue. + */ +struct BrightenFormat { + unsigned int ShiftA; + unsigned int ShiftB; + unsigned int MaskA; + unsigned int MaskB; + unsigned int ScaleShiftA; + unsigned int ScaleShiftB; + unsigned int DownA; + unsigned int DownB; + unsigned int UpA; + unsigned int UpB; + unsigned int ShiftC; + unsigned int ScaleShiftC; + unsigned int DownC; +}; + +BrightenFormat const _Brighten565 = {8, 3, 0xF8, 0xFC, 8, 8, 3, 2, 11, 5, 3, 8, 3}; +BrightenFormat const _Brighten655 = {8, 2, 0xFC, 0xF8, 8, 8, 2, 3, 10, 5, 3, 8, 3}; +BrightenFormat const _Brighten556 = {8, 3, 0xF8, 0xF8, 8, 8, 3, 3, 11, 6, 2, 8, 2}; +BrightenFormat const _Brighten555 = {7, 2, 0xF8, 0xF8, 8, 8, 3, 3, 10, 5, 3, 8, 3}; + + +/// +/// Adds two channel values, holding the result at 255 rather than letting it wrap. +/// +/// One value. +/// The other. +/// unsigned int; The sum, at most 255. +inline unsigned int Add_Saturated(unsigned int left, unsigned int right) +{ + unsigned int const sum = (left & 0xFF) + (right & 0xFF); + return((sum > 255) ? 255 : sum); +} + + +void Brighten_Color(unsigned char const * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, + int colorbuffwidth, int width, int height, BrightenFormat const & format) +{ + unsigned char const * mulrow = mulbuffer; + unsigned char * colorrow = (unsigned char *)colorbuffer; + + for (int y = 0; y < height; y++) { + unsigned char const * mul = mulrow; + unsigned short * color = (unsigned short *)colorrow; + + for (int x = 0; x < width; x++) { + unsigned int const multiplier = *mul; + + if (multiplier != 0) { + unsigned int const pixel = *color; + + unsigned int const a = (pixel >> format.ShiftA) & format.MaskA; + unsigned int const b = (pixel >> format.ShiftB) & format.MaskB; + unsigned int const c = (pixel << format.ShiftC) & 0xFF; + + unsigned int outa = Add_Saturated((a * multiplier) >> format.ScaleShiftA, a); + unsigned int outb = Add_Saturated((b * multiplier) >> format.ScaleShiftB, b); + unsigned int outc = Add_Saturated((c * multiplier) >> format.ScaleShiftC, c); + + outa = (outa >> format.DownA) << format.UpA; + outb = (outb >> format.DownB) << format.UpB; + outc = outc >> format.DownC; + + *color = (unsigned short)(outa | outb | outc); + } + + mul++; + color++; + } + + mulrow += mulbuffwidth; + colorrow += colorbuffwidth; + } +} + + +/* + * How the table-driven brightening puts a pixel back together. The channels arrive already + * separated, so only the reassembly differs between layouts. + */ +struct MmxBrightenFormat { + unsigned int Down; + unsigned int BlueDown; + unsigned int GreenUp; + unsigned int RedUp; + unsigned int Mask; +}; + +/* + * The 655 entry carries 0x423A0A60 where the others carry a channel mask. The assembly treated + * that value as a marker selecting a different reassembly, and then masked green with it as + * well. It is preserved because the recorded output depends on it, not because it reads like a + * mask anyone intended. + */ +unsigned int const MMX_ALTERNATE_MARKER = 0x423A0A60; + +MmxBrightenFormat const _MmxBrighten565 = {2, 1, 5, 10, 0xF8}; +MmxBrightenFormat const _MmxBrighten555 = {3, 0, 5, 10, 0x7C}; +MmxBrightenFormat const _MmxBrighten556 = {2, 0, 6, 10, 0xF8}; +MmxBrightenFormat const _MmxBrighten655 = {2, 1, 4, 10, MMX_ALTERNATE_MARKER}; + + +void MMX_Brighten_Color(unsigned char const * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, + int colorbuffwidth, int width, int height, int const * mmxbuffer, MmxBrightenFormat const & format) +{ + unsigned char const * mulrow = mulbuffer; + unsigned char * colorrow = (unsigned char *)colorbuffer; + + for (int y = 0; y < height; y++) { + unsigned char const * mul = mulrow; + unsigned short * color = (unsigned short *)colorrow; + + for (int x = 0; x < width; x++) { + unsigned int const multiplier = *mul; + + if (multiplier != 0) { + unsigned int const pixel = *color; + unsigned int const entry = (unsigned int)mmxbuffer[pixel]; + + /* + * The table holds the three channels one per byte, which the assembly + * widened to a word each before scaling them together. + */ + unsigned int const blue = entry & 0xFF; + unsigned int const green = (entry >> 8) & 0xFF; + unsigned int const red = (entry >> 16) & 0xFF; + + unsigned int const outblue = Add_Saturated((blue * multiplier) >> 8, blue) >> format.Down; + unsigned int const outgreen = Add_Saturated((green * multiplier) >> 8, green) >> format.Down; + unsigned int const outred = Add_Saturated((red * multiplier) >> 8, red) >> format.Down; + + unsigned int result = outblue >> format.BlueDown; + unsigned int const greenpart = outgreen << format.GreenUp; + unsigned int const redpart = outred << format.RedUp; + + if (format.Mask == MMX_ALTERNATE_MARKER) { + result |= (greenpart & MMX_ALTERNATE_MARKER); + } else { + result |= greenpart; + result |= (redpart & (format.Mask * 256)); + } + + if (format.Mask == MMX_ALTERNATE_MARKER) { + result |= redpart; + } + + *color = (unsigned short)result; + } + + mul++; + color++; + } + + mulrow += mulbuffwidth; + colorrow += colorbuffwidth; + } +} + +} // namespace + + +extern "C" { + +void __cdecl Adjust_Color_565(void * palette, void * translator, int red, int green, int blue, int intensity, void * mask) +{ + Adjust_Color((unsigned char const *)palette, (unsigned short *)translator, red, green, blue, intensity, (unsigned char const *)mask, _Format565); +} + + +void __cdecl Adjust_Color_555(void * palette, void * translator, int red, int green, int blue, int intensity, void * mask) +{ + Adjust_Color((unsigned char const *)palette, (unsigned short *)translator, red, green, blue, intensity, (unsigned char const *)mask, _Format555); +} + + +void __cdecl Adjust_Color_556(void * palette, void * translator, int red, int green, int blue, int intensity, void * mask) +{ + Adjust_Color((unsigned char const *)palette, (unsigned short *)translator, red, green, blue, intensity, (unsigned char const *)mask, _Format556); +} + + +void __cdecl Adjust_Color_655(void * palette, void * translator, int red, int green, int blue, int intensity, void * mask) +{ + Adjust_Color((unsigned char const *)palette, (unsigned short *)translator, red, green, blue, intensity, (unsigned char const *)mask, _Format655); +} + + +void __cdecl Brighten_Color_565(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height) +{ + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, _Brighten565); +} + + +void __cdecl Brighten_Color_555(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height) +{ + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, _Brighten555); +} + + +void __cdecl Brighten_Color_556(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height) +{ + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, _Brighten556); +} + + +void __cdecl Brighten_Color_655(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height) +{ + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, _Brighten655); +} + + +void __cdecl MMX_Brighten_Color_565(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) +{ + MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten565); +} + + +void __cdecl MMX_Brighten_Color_555(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) +{ + MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten555); +} + + +void __cdecl MMX_Brighten_Color_556(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) +{ + MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten556); +} + + +void __cdecl MMX_Brighten_Color_655(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) +{ + MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten655); +} + +} // extern "C" diff --git a/code/interpal.cpp b/code/interpal.cpp deleted file mode 100644 index 861cf0f7..00000000 --- a/code/interpal.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/******************************************************************************* - * O P E N T S - ******************************************************************************* - * SPDX-License-Identifier: GPL-3.0-or-later - * Copyright 2025 Electronic Arts Inc. - * Copyright 2026 OpenTS contributors - * - * Contains material derived from Electronic Arts source code. - * Modified by OpenTS contributors, 2026. - * EA's GPLv3 Section 7 additional terms and supplemental warranty - * disclaimers apply; see LICENSE.md. - ******************************************************************************/ - -/* $Header: /CounterStrike/INTERPAL.CPP 1 3/03/97 10:24a Joe_bostic $ */ -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : Command & Conquer * - * * - * File Name : INTERPAL.CPP * - * * - * Programmer : Steve Tall * - * * - * Start Date : December 7th 1995 * - * * - *---------------------------------------------------------------------------------------------* - * Overview: * - * This module contains functions to allow use of old 320x200 animations on a 640x400 screen * - * * - * Functions: * - * Read_Interpolation_Palette -- reads an interpolation palette table from disk * - * Write_Interpolation_Palette -- writes an interpolation palette to disk * - * Create_Palette_Interpolation_Table -- build the palette interpolation table * - * Increase_Palette_Luminance -- increase the contrast of a palette * - * Interpolate_2X_Scale -- Stretch a 320x200 graphic buffer into 640x400 * - * * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#include "always.h" - -#include "interpal.h" - -#include "ccfile.h" -#include "hsv.h" -#include "misc.h" -#include "palette.h" -#include "surface.h" - -#include - -bool InterpolationPaletteChanged = false; -extern "C" { -extern void __cdecl Asm_Interpolate (unsigned char* src_ptr , - unsigned char* dest_ptr , - int lines , - int src_width , - int dest_width); - -extern void __cdecl Asm_Interpolate_Line_Double (unsigned char* src_ptr , - unsigned char* dest_ptr , - int lines , - int src_width , - int dest_width); - -extern void __cdecl Asm_Interpolate_Line_Interpolate (unsigned char* src_ptr , - unsigned char* dest_ptr , - int lines , - int src_width , - int dest_width); - -} - -extern "C"{ - unsigned char PaletteInterpolationTable[SIZE_OF_PALETTE][SIZE_OF_PALETTE]; - unsigned char * InterpolationPalette; -} - - -/*********************************************************************************************** - * Read_Interpolation_Palette -- reads an interpolation palette table from disk * - * * - * * - * * - * INPUT: name of palette file * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 12/12/95 12:15PM ST : Created * - *=============================================================================================*/ - -void Read_Interpolation_Palette (char const * palette_file_name) -{ - CCFileClass palette_file(palette_file_name); - - if (palette_file.Is_Available()) { - palette_file.Open(FileClass::READ); - palette_file.Read(&PaletteInterpolationTable[0][0], SIZE_OF_PALETTE * SIZE_OF_PALETTE); - palette_file.Close(); - InterpolationPaletteChanged = FALSE; - } -} - - -/*********************************************************************************************** - * Write_Interpolation_Palette -- writes an interpolation palette table to disk * - * * - * * - * * - * INPUT: name of palette file * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 12/12/95 12:15PM ST : Created * - *=============================================================================================*/ - -void Write_Interpolation_Palette (char const * palette_file_name) -{ - CCFileClass palette_file(palette_file_name); - - if (!palette_file.Is_Available()) { - palette_file.Open(FileClass::WRITE); - palette_file.Write(&PaletteInterpolationTable[0][0], SIZE_OF_PALETTE * SIZE_OF_PALETTE); - palette_file.Close(); - } -} - - - - - -/*************************************************************************** - * CREATE_PALETTE_INTERPOLATION_TABLE * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 12/06/1995 MG : Created. * - *=========================================================================*/ -void Create_Palette_Interpolation_Table( void ) -{ - -// Asm_Create_Palette_Interpolation_Table(); - - #if (1) - - int i; - int j; - int p; - unsigned char * first_palette_ptr; - unsigned char * second_palette_ptr; - unsigned char * match_pal_ptr; - int first_r; - int first_g; - int first_b; - int second_r; - int second_g; - int second_b; - int diff_r; - int diff_g; - int diff_b; - int dest_r; - int dest_g; - int dest_b; - int distance; - int closest_distance; - int index_of_closest_color; - - // - // Create an interpolation table for the current palette. - // - first_palette_ptr = (unsigned char *) InterpolationPalette; - for ( i = 0; i < SIZE_OF_PALETTE; i ++ ) { - - // - // Get the first palette entry's RGB. - // - first_r = *first_palette_ptr; - first_palette_ptr ++; - first_g = *first_palette_ptr; - first_palette_ptr ++; - first_b = *first_palette_ptr; - first_palette_ptr ++; - - second_palette_ptr = (unsigned char *) InterpolationPalette; - for ( j = 0; j < SIZE_OF_PALETTE; j ++ ) { - // - // Get the second palette entry's RGB. - // - second_r = *second_palette_ptr; - second_palette_ptr ++; - second_g = *second_palette_ptr; - second_palette_ptr ++; - second_b = *second_palette_ptr; - second_palette_ptr ++; - - // - // Now calculate the RGB halfway between the first and second colors. - // - dest_r = ( first_r + second_r ) >> 1; - dest_g = ( first_g + second_g ) >> 1; - dest_b = ( first_b + second_b ) >> 1; - - // - // Now find the color in the palette that most closely matches the interpolated color. - // - index_of_closest_color = 0; -// closest_distance = (256 * 256) * 3; - closest_distance = 500000; - match_pal_ptr = (unsigned char *) InterpolationPalette; - for ( p = 0; p < SIZE_OF_PALETTE; p ++ ) { - diff_r = ( ((int) (*match_pal_ptr)) - dest_r ); - match_pal_ptr ++; - diff_g = ( ((int) (*match_pal_ptr)) - dest_g ); - match_pal_ptr ++; - diff_b = ( ((int) (*match_pal_ptr)) - dest_b ); - match_pal_ptr ++; - - distance = ( diff_r * diff_r ) + ( diff_g * diff_g ) + ( diff_b * diff_b ); - if ( distance < closest_distance ) { - closest_distance = distance; - index_of_closest_color = p; - } - } - - PaletteInterpolationTable[ i ][ j ] = (unsigned char) index_of_closest_color; - } - } - - #endif - InterpolationPaletteChanged = FALSE; - return; - -} - - -/*********************************************************************************************** - * Increase_Palette_Luminance -- increase contrast of colours in a palette * - * * - * * - * * - * INPUT: ptr to palette * - * percentage increase of red * - * percentage increase of green * - * percentage increase of blue * - * cap value for colours * - * * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 12/12/95 12:16PM ST : Created * - *=============================================================================================*/ - -void Increase_Palette_Luminance (PaletteClass & palette , double percentage) -{ - for (int i=0 ; iLock(); - if (src_ptr != NULL) { - source_locked = true; - } - - dest_ptr = (unsigned char *)dest->Lock(); - if (dest_ptr != NULL) { - dest_locked = true; - } - - if (dest_locked && source_locked) { - - // - // Get width of source and dest buffers. - // - src_width = source->Get_Width(); - dest_width = 2*(dest->Stride()); - - /* - ** Call the appropriate assembly language copy routine - */ -#if (1) - switch (CopyType) { - case 0: - Asm_Interpolate ( src_ptr , dest_ptr , source->Get_Height() , src_width , dest_width); - break; - - case 1: - Asm_Interpolate_Line_Double( src_ptr , dest_ptr , source->Get_Height() , src_width , dest_width); - break; - - case 2: - Asm_Interpolate_Line_Interpolate( src_ptr , dest_ptr , source->Get_Height() , src_width , dest_width); - break; - } -#endif - -#if (0) - // - // Copy over the first pixel (upper left). - // - *dest_ptr = *src_ptr; - - src_ptr ++; - dest_ptr ++; - - // - // Scale copy. - // - width_counter = 0; - while ( src_ptr < end_of_source ) { - - // - // Blend this pixel with the one to the left and place this new color in the dest buffer. - // - *dest_ptr = PaletteInterpolationTable[ (*src_ptr) ][ (*( src_ptr - 1 )) ]; - dest_ptr ++; - - // - // Now place the source pixel into the dest buffer. - // - *dest_ptr = *src_ptr; - - src_ptr ++; - dest_ptr ++; - - width_counter ++; - if ( width_counter == src_width ) { - width_counter = 0; - last_dest_ptr += dest_width; - dest_ptr = last_dest_ptr; - } - } -#endif - } - - if (source_locked) source->Unlock(); - if (dest_locked) dest->Unlock(); -} diff --git a/code/interpal.h b/code/interpal.h deleted file mode 100644 index 0b3f8aa5..00000000 --- a/code/interpal.h +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* - * O P E N T S - ******************************************************************************* - * SPDX-License-Identifier: GPL-3.0-or-later - * Copyright 2025 Electronic Arts Inc. - * Copyright 2026 OpenTS contributors - * - * Contains material derived from Electronic Arts source code. - * Modified by OpenTS contributors, 2026. - * EA's GPLv3 Section 7 additional terms and supplemental warranty - * disclaimers apply; see LICENSE.md. - ******************************************************************************/ - -#pragma once - -class Surface; -class PaletteClass; - -#define SIZE_OF_PALETTE 256 -extern "C" unsigned char *InterpolationPalette; -extern bool InterpolationPaletteChanged; -void Interpolate_2X_Scale( Surface * source, Surface * dest , char const * palette_file_name); -void Read_Interpolation_Palette (char const *palette_file_name); -void Write_Interpolation_Palette (char const *palette_file_name); -void Increase_Palette_Luminance (PaletteClass & palette , double percentage); -extern "C"{ - extern unsigned char PaletteInterpolationTable[SIZE_OF_PALETTE][SIZE_OF_PALETTE]; - extern unsigned char *InterpolationPalette; - void __cdecl Asm_Create_Palette_Interpolation_Table(void); -} diff --git a/code/voxlib.cpp b/code/voxlib.cpp index 21df08d8..895c50c9 100644 --- a/code/voxlib.cpp +++ b/code/voxlib.cpp @@ -36,38 +36,12 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state); void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state); void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state); -extern "C" { -void __cdecl Draw_Voxel_Regular_Normals_ASM(VoxelFuncArgumentStruct * state); -void __cdecl Draw_Voxel_Reverse_Normals_ASM(VoxelFuncArgumentStruct * state); -void __cdecl Draw_Voxel_Regular_Lighting_Normals_ASM(VoxelFuncArgumentStruct * state); -void __cdecl Draw_Voxel_Reverse_Lighting_Normals_ASM(VoxelFuncArgumentStruct * state); -void __cdecl Draw_Voxel_Regular_ASM(VoxelFuncArgumentStruct * state); -void __cdecl Draw_Voxel_Reverse_ASM(VoxelFuncArgumentStruct * state); -void __cdecl Draw_Voxel_UNUSED1_ASM(VoxelFuncArgumentStruct * state); -void __cdecl Draw_Voxel_UNUSED2_ASM(VoxelFuncArgumentStruct * state); -} - -VoxelFuncPtr VoxelDrawFunctions[32] = { - - /// Assembly routines - &Draw_Voxel_Regular_Normals_ASM, - &Draw_Voxel_Reverse_Normals_ASM, - &Draw_Voxel_Regular_Normals_ZBuffer, - &Draw_Voxel_Reverse_Normals_ZBuffer, - &Draw_Voxel_Regular_Lighting_Normals_ASM, - &Draw_Voxel_Reverse_Lighting_Normals_ASM, - &Draw_Voxel_Regular_Normals_ZBuffer_Lighting, - &Draw_Voxel_Reverse_Normals_ZBuffer_Lighting, - &Draw_Voxel_Regular_ASM, - &Draw_Voxel_Reverse_ASM, - &Draw_Voxel_Regular_ZBuffer, - &Draw_Voxel_Reverse_ZBuffer, - &Draw_Voxel_Regular_ASM, - &Draw_Voxel_Reverse_ASM, - &Draw_Voxel_Regular_ZBuffer, - &Draw_Voxel_Reverse_ZBuffer, - - /// The same set again, with the C++ drawers in place of the assembly ones. +/* + * Indexed by the orientation's direction together with the depth buffer, lighting and normal + * type switches, which is why the last four entries repeat the four before them: the normal + * type does not change which drawer is wanted once lighting is off. + */ +VoxelFuncPtr VoxelDrawFunctions[16] = { &Draw_Voxel_Regular_Normals, &Draw_Voxel_Reverse_Normals, &Draw_Voxel_Regular_Normals_ZBuffer, @@ -1120,9 +1094,11 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) */ ptr++; - /// Compute buffer index and write color + /// Compute buffer index and write color. A voxel covers two + /// buffer bytes, so the colour goes down twice. unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); VoxelDrawBuffer[buffer_index] = color_index; + VoxelDrawBuffer[buffer_index + 1] = color_index; pixel_x += state->TransformMatrix[3].I; pixel_y += state->TransformMatrix[3].J; @@ -1206,9 +1182,11 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr--; - /// Compute buffer index and write color + /// Compute buffer index and write color. A voxel covers two + /// buffer bytes, so the colour goes down twice. unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); VoxelDrawBuffer[buffer_index] = color_index; + VoxelDrawBuffer[buffer_index + 1] = color_index; pixel_x += state->TransformMatrix[3].I; pixel_y += state->TransformMatrix[3].J; @@ -1986,10 +1964,16 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr++; +<<<<<<< HEAD /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); VoxelDrawBuffer[buffer_index] = color_index; VoxelDrawBuffer[buffer_index + 1] = color_index; +======= + /// Compute buffer index and write color. Unlike the shaded + /// drawers, this one covers a single buffer byte per voxel. + VoxelDrawBuffer[(pixel_x >> 8) | (pixel_y & 0xFF00)] = color_index; +>>>>>>> 0fef683 (Translate voxel drawing and colour operations to C++) pixel_x += state->TransformMatrix[3].I; pixel_y += state->TransformMatrix[3].J; @@ -2067,10 +2051,16 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr--; +<<<<<<< HEAD /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); VoxelDrawBuffer[buffer_index] = color_index; VoxelDrawBuffer[buffer_index + 1] = color_index; +======= + /// Compute buffer index and write color. Unlike the shaded + /// drawers, this one covers a single buffer byte per voxel. + VoxelDrawBuffer[(pixel_x >> 8) | (pixel_y & 0xFF00)] = color_index; +>>>>>>> 0fef683 (Translate voxel drawing and colour operations to C++) pixel_x += state->TransformMatrix[3].I; pixel_y += state->TransformMatrix[3].J; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 785dd4b5..d7a35e0d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,4 +5,5 @@ add_subdirectory(logstress) add_subdirectory(netpacket) add_subdirectory(sosparity) add_subdirectory(spawner) -add_subdirectory(syncrec) +add_subdirectory(colorops) +add_subdirectory(voxeldraw) diff --git a/tests/colorops/CMakeLists.txt b/tests/colorops/CMakeLists.txt new file mode 100644 index 00000000..fcd102ad --- /dev/null +++ b/tests/colorops/CMakeLists.txt @@ -0,0 +1,30 @@ +# The colour routines are compiled straight into the harness. It lives outside code/ so that the +# recursive glob building OpenTS cannot pick this target's entry point up. +add_executable(ColorOps + "${CMAKE_CURRENT_SOURCE_DIR}/coloropstest.cpp" + "${CMAKE_SOURCE_DIR}/code/colorops.cpp" +) + +target_compile_features(ColorOps PRIVATE cxx_std_20) + +target_include_directories(ColorOps PRIVATE + "${CMAKE_SOURCE_DIR}/code" + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_compile_definitions(ColorOps PRIVATE WIN32 _WINDOWS _MBCS) + +# The engine builds this source with SSE2 and precise floating point. The harness matches that +# so a result here carries over to the engine. +target_compile_options(ColorOps PRIVATE + $<$:/MTd /EHsc /Zc:__cplusplus /arch:SSE2 /fp:precise> + $<$:/MT /EHsc /Zc:__cplusplus /arch:SSE2 /fp:precise> +) + +target_link_libraries(ColorOps PRIVATE kernel32 user32 shell32) + +set_target_properties(ColorOps PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" +) + +add_test(NAME colorops COMMAND ColorOps) diff --git a/tests/colorops/colorgolden.h b/tests/colorops/colorgolden.h new file mode 100644 index 00000000..fdd1a910 --- /dev/null +++ b/tests/colorops/colorgolden.h @@ -0,0 +1,126 @@ +/******************************************************************************* + * O P E N T S + ******************************************************************************* + * SPDX-License-Identifier: GPL-3.0-or-later + * Copyright 2026 OpenTS contributors + * + * See LICENSE.md for applicable additional terms and warranty disclaimers. + ******************************************************************************/ + +// Generated from the palette tinting and spot light brightening routines while they were +// still hand-written assembly, and kept so the C++ that replaced them can be held to the +// same output. +// +// Generated file. Do not hand-edit. + +#pragma once + +struct AdjustGoldenCase { + int Mode; + int Tint; + unsigned int Seed; + unsigned long long Hash; +}; + +static AdjustGoldenCase const AdjustGoldenCases[] = { + {0, 0, 16110u, 12760808774863403491ULL}, + {0, 1, 24029u, 11632925425805831495ULL}, + {0, 2, 31948u, 5925570506153992127ULL}, + {0, 3, 39867u, 13047089033812385797ULL}, + {0, 4, 47786u, 16473988446431455303ULL}, + {1, 0, 55705u, 7840847192367313613ULL}, + {1, 1, 63624u, 15986945065950998622ULL}, + {1, 2, 71543u, 16620328751264269474ULL}, + {1, 3, 79462u, 2197127037031984214ULL}, + {1, 4, 87381u, 16652304632587527866ULL}, + {2, 0, 95300u, 2020184679552769531ULL}, + {2, 1, 103219u, 11395269755789222990ULL}, + {2, 2, 111138u, 8778564327958451480ULL}, + {2, 3, 119057u, 11297123781214576017ULL}, + {2, 4, 126976u, 10099781733166984675ULL}, + {3, 0, 134895u, 2908014413764433922ULL}, + {3, 1, 142814u, 3380677557574597077ULL}, + {3, 2, 150733u, 2032283341979249887ULL}, + {3, 3, 158652u, 16316237050576502971ULL}, + {3, 4, 166571u, 15216183069698100778ULL}, +}; + +static int const AdjustGoldenCaseCount = 20; + +struct BrightenGoldenCase { + int Mode; + int Mmx; + int Width; + int Height; + unsigned int Seed; + unsigned long long Hash; +}; + +static BrightenGoldenCase const BrightenGoldenCases[] = { + {0, 0, 1, 1, 174490u, 9683954061780082186ULL}, + {0, 0, 2, 1, 182409u, 3585589939020540445ULL}, + {0, 0, 7, 3, 190328u, 12646124570177522196ULL}, + {0, 0, 16, 4, 198247u, 8855089449368412364ULL}, + {0, 0, 33, 9, 206166u, 4161396504343120247ULL}, + {0, 0, 64, 16, 214085u, 7491337042742393889ULL}, + {0, 0, 128, 32, 222004u, 1562462105826136594ULL}, + {0, 0, 255, 64, 229923u, 12977303894793765084ULL}, + {0, 1, 1, 1, 237842u, 2534684662198146892ULL}, + {0, 1, 2, 1, 245761u, 9679803194961330382ULL}, + {0, 1, 7, 3, 253680u, 2549577378279256583ULL}, + {0, 1, 16, 4, 261599u, 11676825973235883859ULL}, + {0, 1, 33, 9, 269518u, 13545447451985782494ULL}, + {0, 1, 64, 16, 277437u, 4102005335375077591ULL}, + {0, 1, 128, 32, 285356u, 3889344650472255677ULL}, + {0, 1, 255, 64, 293275u, 3297543697270025883ULL}, + {1, 0, 1, 1, 301194u, 13186354609198225149ULL}, + {1, 0, 2, 1, 309113u, 13814059303084228345ULL}, + {1, 0, 7, 3, 317032u, 10720627840618582556ULL}, + {1, 0, 16, 4, 324951u, 18012041115974557435ULL}, + {1, 0, 33, 9, 332870u, 7090443837710868316ULL}, + {1, 0, 64, 16, 340789u, 7935162482590007511ULL}, + {1, 0, 128, 32, 348708u, 16754602968852868577ULL}, + {1, 0, 255, 64, 356627u, 11578321534074525250ULL}, + {1, 1, 1, 1, 364546u, 10427039056597764142ULL}, + {1, 1, 2, 1, 372465u, 1748292752117078850ULL}, + {1, 1, 7, 3, 380384u, 10317547240677326599ULL}, + {1, 1, 16, 4, 388303u, 16604617947182860757ULL}, + {1, 1, 33, 9, 396222u, 1318537032546736748ULL}, + {1, 1, 64, 16, 404141u, 9229413794311576209ULL}, + {1, 1, 128, 32, 412060u, 7340557553286926667ULL}, + {1, 1, 255, 64, 419979u, 5071078941017253528ULL}, + {2, 0, 1, 1, 427898u, 10459444610915521759ULL}, + {2, 0, 2, 1, 435817u, 9809152111208362860ULL}, + {2, 0, 7, 3, 443736u, 5974842822965084410ULL}, + {2, 0, 16, 4, 451655u, 14016269938534619012ULL}, + {2, 0, 33, 9, 459574u, 11686188751530981124ULL}, + {2, 0, 64, 16, 467493u, 16824327894963774702ULL}, + {2, 0, 128, 32, 475412u, 831560034207278086ULL}, + {2, 0, 255, 64, 483331u, 10597710443419274145ULL}, + {2, 1, 1, 1, 491250u, 8479100877978498426ULL}, + {2, 1, 2, 1, 499169u, 7481949699832809259ULL}, + {2, 1, 7, 3, 507088u, 16607636731006922296ULL}, + {2, 1, 16, 4, 515007u, 6405581235097048851ULL}, + {2, 1, 33, 9, 522926u, 822099569615870640ULL}, + {2, 1, 64, 16, 530845u, 8266273084601642906ULL}, + {2, 1, 128, 32, 538764u, 8535626501608830796ULL}, + {2, 1, 255, 64, 546683u, 3737545516508015044ULL}, + {3, 0, 1, 1, 554602u, 3476118273324028887ULL}, + {3, 0, 2, 1, 562521u, 3460303321212174411ULL}, + {3, 0, 7, 3, 570440u, 5507246755901068217ULL}, + {3, 0, 16, 4, 578359u, 2761380345813287195ULL}, + {3, 0, 33, 9, 586278u, 14881774169913704698ULL}, + {3, 0, 64, 16, 594197u, 13329692175776703259ULL}, + {3, 0, 128, 32, 602116u, 16441757303667149227ULL}, + {3, 0, 255, 64, 610035u, 2060866494282096795ULL}, + {3, 1, 1, 1, 617954u, 11405787290677921704ULL}, + {3, 1, 2, 1, 625873u, 6279770659411831877ULL}, + {3, 1, 7, 3, 633792u, 10521531452208876928ULL}, + {3, 1, 16, 4, 641711u, 14797326666873277565ULL}, + {3, 1, 33, 9, 649630u, 7304885447097531915ULL}, + {3, 1, 64, 16, 657549u, 15330689263602870827ULL}, + {3, 1, 128, 32, 665468u, 10892574876935284254ULL}, + {3, 1, 255, 64, 673387u, 10579957447657776596ULL}, +}; + +static int const BrightenGoldenCaseCount = 64; diff --git a/tests/colorops/coloropstest.cpp b/tests/colorops/coloropstest.cpp new file mode 100644 index 00000000..00d8b941 --- /dev/null +++ b/tests/colorops/coloropstest.cpp @@ -0,0 +1,173 @@ +/******************************************************************************* + * O P E N T S + ******************************************************************************* + * SPDX-License-Identifier: GPL-3.0-or-later + * Copyright 2026 OpenTS contributors + * + * See LICENSE.md for applicable additional terms and warranty disclaimers. + ******************************************************************************/ + +// Holds the palette tinting and spot light brightening in colorops.cpp to the output the +// assembly they replaced produced. The vectors in colorgolden.h were recorded from that +// assembly before it was removed; the three hand-written paths through Adjust_Color agreed +// with one another when they were recorded, so one set of vectors covers all of them. +// Needs no game data. + +#include +#include + +#include "colorgolden.h" + +extern "C" { +void __cdecl Adjust_Color_565(void *pal, void *xlat, int r, int g, int b, int i, void *mask); +void __cdecl Adjust_Color_555(void *pal, void *xlat, int r, int g, int b, int i, void *mask); +void __cdecl Adjust_Color_556(void *pal, void *xlat, int r, int g, int b, int i, void *mask); +void __cdecl Adjust_Color_655(void *pal, void *xlat, int r, int g, int b, int i, void *mask); + +void __cdecl Brighten_Color_565(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h); +void __cdecl Brighten_Color_555(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h); +void __cdecl Brighten_Color_556(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h); +void __cdecl Brighten_Color_655(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h); + +void __cdecl MMX_Brighten_Color_565(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); +void __cdecl MMX_Brighten_Color_555(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); +void __cdecl MMX_Brighten_Color_556(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); +void __cdecl MMX_Brighten_Color_655(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); +} + +namespace { + +unsigned char Palette[256 * 3]; +unsigned char Mask[256]; +unsigned short Translator[256]; + +unsigned char MulBuffer[256 * 256]; +unsigned short ColorBuffer[512 * 512]; +int MmxBuffer[65536]; + +unsigned int Seed = 0; + +int Failures = 0; +int Checked = 0; + + +unsigned int Next_Random(void) +{ + Seed = Seed * 1103515245u + 12345u; + return(Seed >> 8); +} + + +unsigned long long Hash(void const * data, int size) +{ + unsigned char const * bytes = (unsigned char const *)data; + unsigned long long hash = 1469598103934665603ULL; + for (int i = 0; i < size; i++) { + hash ^= (unsigned long long)bytes[i]; + hash *= 1099511628211ULL; + } + return(hash); +} + + +typedef void (__cdecl * AdjustFunc)(void *, void *, int, int, int, int, void *); +typedef void (__cdecl * BrightenFunc)(unsigned char *, unsigned short *, int, int, int, int); +typedef void (__cdecl * MmxBrightenFunc)(unsigned char *, unsigned short *, int, int, int, int, int *); + +AdjustFunc const Adjusts[4] = {Adjust_Color_565, Adjust_Color_555, Adjust_Color_556, Adjust_Color_655}; +BrightenFunc const Brightens[4] = {Brighten_Color_565, Brighten_Color_555, Brighten_Color_556, Brighten_Color_655}; +MmxBrightenFunc const MmxBrightens[4] = {MMX_Brighten_Color_565, MMX_Brighten_Color_555, MMX_Brighten_Color_556, MMX_Brighten_Color_655}; + +char const * const ModeNames[4] = {"565", "555", "556", "655"}; + + +// Must reproduce the generator's inputs exactly or every vector misses. +void Fill_Adjust_Inputs(unsigned int seed) +{ + Seed = seed; + for (int i = 0; i < 256 * 3; i++) { + Palette[i] = (unsigned char)(Next_Random() & 0xFF); + } + for (int i = 0; i < 256; i++) { + Mask[i] = (unsigned char)((Next_Random() & 1) ? 1 : 0); + } +} + + +struct Tint { + int Red; + int Green; + int Blue; + int Intensity; +}; + +Tint const Tints[] = { + {0x10000, 0x10000, 0x10000, 0x10000}, + {0x08000, 0x0C000, 0x10000, 0x06000}, + {0x1FFFF, 0x18000, 0x04000, 0x1C000}, + {0x00000, 0x10000, 0x20000, 0x00000}, + {0x30000, 0x30000, 0x30000, 0x02000} +}; + +} // namespace + + +int main(void) +{ + for (int i = 0; i < AdjustGoldenCaseCount; i++) { + AdjustGoldenCase const & test = AdjustGoldenCases[i]; + + Fill_Adjust_Inputs(test.Seed); + std::memset(Translator, 0xA5, sizeof(Translator)); + + Adjusts[test.Mode](Palette, Translator, Tints[test.Tint].Red, Tints[test.Tint].Green, + Tints[test.Tint].Blue, Tints[test.Tint].Intensity, Mask); + + unsigned long long const hash = Hash(Translator, sizeof(Translator)); + + if (hash != test.Hash) { + std::printf("FAILED Adjust_Color_%s tint %d: expected %llu, got %llu\n", + ModeNames[test.Mode], test.Tint, test.Hash, hash); + Failures++; + } + + Checked++; + } + + for (int i = 0; i < BrightenGoldenCaseCount; i++) { + BrightenGoldenCase const & test = BrightenGoldenCases[i]; + + Seed = test.Seed; + + for (int j = 0; j < 256 * 256; j++) { + MulBuffer[j] = (unsigned char)(Next_Random() & 0xFF); + } + for (int j = 0; j < 512 * 512; j++) { + ColorBuffer[j] = (unsigned short)(Next_Random() & 0xFFFF); + } + for (int j = 0; j < 65536; j++) { + MmxBuffer[j] = (int)(Next_Random() & 0x00FFFFFF); + } + + if (test.Mmx != 0) { + MmxBrightens[test.Mode](MulBuffer, ColorBuffer, 256, 512 * 2, test.Width, test.Height, MmxBuffer); + } else { + Brightens[test.Mode](MulBuffer, ColorBuffer, 256, 512 * 2, test.Width, test.Height); + } + + unsigned long long const hash = Hash(ColorBuffer, 512 * 512 * 2); + + if (hash != test.Hash) { + std::printf("FAILED %sBrighten_Color_%s %dx%d: expected %llu, got %llu\n", + test.Mmx ? "MMX_" : "", ModeNames[test.Mode], test.Width, test.Height, test.Hash, hash); + Failures++; + } + + Checked++; + } + + std::printf("%-52s %s\n", "Colour tinting and brightening match the assembly", Failures == 0 ? "ok" : "FAILED"); + std::printf("checked %d cases, %d mismatches\n", Checked, Failures); + + return(Failures == 0 ? 0 : 1); +} diff --git a/tests/voxeldraw/CMakeLists.txt b/tests/voxeldraw/CMakeLists.txt new file mode 100644 index 00000000..0a69d368 --- /dev/null +++ b/tests/voxeldraw/CMakeLists.txt @@ -0,0 +1,30 @@ +# The voxel library is compiled straight into the harness. It lives outside code/ so that the +# recursive glob building OpenTS cannot pick this target's entry point up. +add_executable(VoxelDraw + "${CMAKE_CURRENT_SOURCE_DIR}/voxeldraw.cpp" + "${CMAKE_SOURCE_DIR}/code/voxlib.cpp" +) + +target_compile_features(VoxelDraw PRIVATE cxx_std_20) + +target_include_directories(VoxelDraw PRIVATE + "${CMAKE_SOURCE_DIR}/code" + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_compile_definitions(VoxelDraw PRIVATE WIN32 _WINDOWS _MBCS) + +# The engine builds this source with SSE2 and precise floating point. The harness matches that +# so a result here carries over to the engine. +target_compile_options(VoxelDraw PRIVATE + $<$:/MTd /EHsc /Zc:__cplusplus /arch:SSE2 /fp:precise> + $<$:/MT /EHsc /Zc:__cplusplus /arch:SSE2 /fp:precise> +) + +target_link_libraries(VoxelDraw PRIVATE kernel32 user32 shell32) + +set_target_properties(VoxelDraw PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" +) + +add_test(NAME voxeldraw COMMAND VoxelDraw) diff --git a/tests/voxeldraw/voxeldraw.cpp b/tests/voxeldraw/voxeldraw.cpp new file mode 100644 index 00000000..ea8e99f9 --- /dev/null +++ b/tests/voxeldraw/voxeldraw.cpp @@ -0,0 +1,232 @@ +/******************************************************************************* + * O P E N T S + ******************************************************************************* + * SPDX-License-Identifier: GPL-3.0-or-later + * Copyright 2026 OpenTS contributors + * + * See LICENSE.md for applicable additional terms and warranty disclaimers. + ******************************************************************************/ + +// Holds the six voxel drawers in voxlib.cpp to the output the assembly they replaced produced. +// The vectors in voxelgolden.h were recorded from that assembly before it was removed. +// +// These drawers were reached only through entries 16 to 31 of VoxelDrawFunctions, which the +// dispatch never indexed, so until that table was repointed none of this code had ever run and +// nothing would have noticed it drawing the wrong thing. Needs no game data. + +#include +#include +#include + +#include "voxdrsys.h" +#include "voxlib.h" + +#include "voxelgolden.h" + +void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state); +void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state); +void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state); +void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state); +void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state); +void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state); + +/* + * Standing in for voxdrsys.cpp, which the harness does not build. The draw buffer is larger + * than the engine's so that a drawer overrunning it is caught here rather than corrupting + * whatever the engine happens to place next to it. + */ +extern "C" { +unsigned char VoxelDrawBuffer[262144]; +unsigned char VoxelDrawZBuffer[262144]; +unsigned char VoxelPaletteTranslateTable[MAX_PALETTE_LOOKUP_ENTRIES][VOXEL_PALETTE_SIZE]; +} + +RGBStruct VoxelRGBColors[VOXEL_PALETTE_SIZE]; + +namespace VoxelDrawSystem { + BOOL EnableLighting = 0; + BOOL EnableZBuffer = 0; +} + +Matrix3D::Matrix3D(float * const) {} +VoxelPaletteLibrary::VoxelPaletteLibrary(RGBStruct *, void *) {} +VoxelPaletteLibrary::~VoxelPaletteLibrary(void) {} +void VoxelPaletteLibrary::Calculate_Lookup_Table(float *, int) {} + +namespace { + +int const SPANMAX = 4096; +int const DATAMAX = 65536; + +unsigned char StartOffsets[SPANMAX]; +unsigned char EndOffsets[SPANMAX]; +unsigned char VoxelData[DATAMAX]; + +unsigned int Seed = 0; + +int Failures = 0; +int Checked = 0; + + +unsigned int Next_Random(void) +{ + Seed = Seed * 1103515245u + 12345u; + return(Seed >> 8); +} + + +unsigned long long Hash(unsigned char const * data, int size) +{ + unsigned long long hash = 1469598103934665603ULL; + for (int i = 0; i < size; i++) { + hash ^= (unsigned long long)data[i]; + hash *= 1099511628211ULL; + } + return(hash); +} + +typedef void (* Drawer)(VoxelFuncArgumentStruct *); + +Drawer const Drawers[6] = { + Draw_Voxel_Regular_Normals, + Draw_Voxel_Reverse_Normals, + Draw_Voxel_Regular_Normals_Lighting, + Draw_Voxel_Reverse_Normals_Lighting, + Draw_Voxel_Regular, + Draw_Voxel_Reverse +}; + +char const * const Names[6] = { + "Draw_Voxel_Regular_Normals", + "Draw_Voxel_Reverse_Normals", + "Draw_Voxel_Regular_Normals_Lighting", + "Draw_Voxel_Reverse_Normals_Lighting", + "Draw_Voxel_Regular", + "Draw_Voxel_Reverse" +}; + + +/* + * Must build byte for byte what the generator built. + * + * A column's spans have to account for exactly ZSize voxels between them, because the drawers + * count down from ZSize and stop on zero; a column adding up to anything else takes the counter + * past it and the walk runs away through the data. The column table holds 32 bit offsets and a + * negative entry means an empty column. Each span ends with a repeat of its length, which the + * forward drawers step over and the reverse drawers read first. + */ +void Build_Layer(unsigned int seed, int columns, int zsize, bool withnormals) +{ + Seed = seed; + + unsigned int * starts = (unsigned int *)StartOffsets; + unsigned int * ends = (unsigned int *)EndOffsets; + + int at = 0; + + for (int i = 0; i < columns; i++) { + + if ((Next_Random() % 8) == 0) { + starts[i] = UINT_MAX; + ends[i] = UINT_MAX; + continue; + } + + starts[i] = (unsigned int)at; + + int remaining = zsize; + + while (remaining > 0) { + int const skip = (int)(Next_Random() % (unsigned int)remaining); + remaining -= skip; + + int const run = 1 + (int)(Next_Random() % (unsigned int)remaining); + remaining -= run; + + VoxelData[at++] = (unsigned char)skip; + VoxelData[at++] = (unsigned char)run; + + /* + * A voxel is a colour and a normal for the drawers that shade, and a colour + * on its own for the two that do not. + */ + for (int v = 0; v < run; v++) { + VoxelData[at++] = (unsigned char)(1 + (Next_Random() % 254)); + + if (withnormals) { + VoxelData[at++] = (unsigned char)(Next_Random() % 244); + } + } + + VoxelData[at++] = (unsigned char)run; + } + + ends[i] = (unsigned int)(at - 1); + } + + for (int i = 0; i < 256 * 3; i++) { + ((unsigned char *)VoxelRGBColors)[i] = (unsigned char)(Next_Random() & 0xFF); + } + + for (int i = 0; i < MAX_PALETTE_LOOKUP_ENTRIES; i++) { + for (int j = 0; j < VOXEL_PALETTE_SIZE; j++) { + VoxelPaletteTranslateTable[i][j] = (unsigned char)(Next_Random() & 0xFF); + } + } +} + + +void Setup(VoxelFuncArgumentStruct & arg) +{ + std::memset(&arg, 0, sizeof(arg)); + + arg.StartOffset = StartOffsets; + arg.EndOffset = EndOffsets; + arg.DataOffset = VoxelData; + arg.StartIndex = 24; + arg.StrideX = 1; + arg.StrideY = 4; + + for (int i = 0; i < 4; i++) { + arg.TransformMatrix[i].I = (short)(64 + i * 16); + arg.TransformMatrix[i].J = (short)(48 + i * 8); + arg.TransformMatrix[i].K = (short)(32 + i * 4); + } + + arg.XSize = 4; + arg.YSize = 4; + arg.ZSize = 8; +} + +} // namespace + + +int main(void) +{ + for (int i = 0; i < VoxelGoldenCaseCount; i++) { + VoxelGoldenCase const & test = VoxelGoldenCases[i]; + + Build_Layer(test.Seed, 64, 8, test.Which < 4); + + VoxelFuncArgumentStruct arg; + std::memset(VoxelDrawBuffer, 0, sizeof(VoxelDrawBuffer)); + Setup(arg); + + Drawers[test.Which](&arg); + + unsigned long long const hash = Hash(VoxelDrawBuffer, sizeof(VoxelDrawBuffer)); + + if (hash != test.Hash) { + std::printf("FAILED %-38s seed %u: expected %llu, got %llu\n", + Names[test.Which], test.Seed, test.Hash, hash); + Failures++; + } + + Checked++; + } + + std::printf("%-52s %s\n", "Voxel drawing matches the recorded assembly", Failures == 0 ? "ok" : "FAILED"); + std::printf("checked %d cases, %d mismatches\n", Checked, Failures); + + return(Failures == 0 ? 0 : 1); +} diff --git a/tests/voxeldraw/voxelgolden.h b/tests/voxeldraw/voxelgolden.h new file mode 100644 index 00000000..af3f4d9e --- /dev/null +++ b/tests/voxeldraw/voxelgolden.h @@ -0,0 +1,171 @@ +/******************************************************************************* + * O P E N T S + ******************************************************************************* + * SPDX-License-Identifier: GPL-3.0-or-later + * Copyright 2026 OpenTS contributors + * + * See LICENSE.md for applicable additional terms and warranty disclaimers. + ******************************************************************************/ + +// Generated from the voxel drawers while they were still hand-written assembly, and kept +// so the C++ that replaced them can be held to the same output. Each row is one drawer +// run over a generated layer, hashed across the whole draw buffer. +// +// Generated file. Do not hand-edit. + +#pragma once + +struct VoxelGoldenCase { + int Which; + unsigned int Seed; + unsigned long long Hash; +}; + +static VoxelGoldenCase const VoxelGoldenCases[] = { + {0, 28169u, 13324653092316034450ULL}, + {0, 36088u, 12351699151280656429ULL}, + {0, 44007u, 17199592110331691751ULL}, + {0, 51926u, 15390681673580776202ULL}, + {0, 59845u, 2825425979693356026ULL}, + {0, 67764u, 25800052190659043ULL}, + {0, 75683u, 7325842616049640313ULL}, + {0, 83602u, 17645968187554184191ULL}, + {0, 91521u, 9525590033643036072ULL}, + {0, 99440u, 10585983704101342410ULL}, + {0, 107359u, 10204120045907133699ULL}, + {0, 115278u, 11130510175161308529ULL}, + {0, 123197u, 5767097110549188921ULL}, + {0, 131116u, 5235687674598385644ULL}, + {0, 139035u, 9005539365649528394ULL}, + {0, 146954u, 18425927706755742343ULL}, + {0, 154873u, 947132574381123500ULL}, + {0, 162792u, 2943253927102308ULL}, + {0, 170711u, 11354915360533545630ULL}, + {0, 178630u, 12938560224086218970ULL}, + {0, 186549u, 6735834921435141727ULL}, + {0, 194468u, 4620132221512080041ULL}, + {0, 202387u, 6805978274876668650ULL}, + {0, 210306u, 3062081007018294060ULL}, + {1, 218225u, 5518851115440504590ULL}, + {1, 226144u, 17766976509397856527ULL}, + {1, 234063u, 21458341796674991ULL}, + {1, 241982u, 9668340853698928506ULL}, + {1, 249901u, 11070411440877969667ULL}, + {1, 257820u, 3412966419792104896ULL}, + {1, 265739u, 1644744544794223772ULL}, + {1, 273658u, 18215157723010317950ULL}, + {1, 281577u, 13494821044585903190ULL}, + {1, 289496u, 15635478134736993356ULL}, + {1, 297415u, 3676630468166872938ULL}, + {1, 305334u, 1650428375562877262ULL}, + {1, 313253u, 7635345958887419688ULL}, + {1, 321172u, 2156384056444245913ULL}, + {1, 329091u, 16799683983158384103ULL}, + {1, 337010u, 7022508193269267110ULL}, + {1, 344929u, 14506774546798531577ULL}, + {1, 352848u, 18199756956898249519ULL}, + {1, 360767u, 17470699965221551398ULL}, + {1, 368686u, 225776899552830475ULL}, + {1, 376605u, 3449402144847509193ULL}, + {1, 384524u, 13050037680469517880ULL}, + {1, 392443u, 9010391954831812739ULL}, + {1, 400362u, 6942504870830098237ULL}, + {2, 408281u, 15798523031825813403ULL}, + {2, 416200u, 4507558737198793848ULL}, + {2, 424119u, 3851442749804437763ULL}, + {2, 432038u, 930039072865289532ULL}, + {2, 439957u, 14918691864484818114ULL}, + {2, 447876u, 1900814372412917523ULL}, + {2, 455795u, 9880610814969945598ULL}, + {2, 463714u, 12235921528745917133ULL}, + {2, 471633u, 17295491051951213915ULL}, + {2, 479552u, 8208964221764546070ULL}, + {2, 487471u, 15498567043124049416ULL}, + {2, 495390u, 11601304743621742993ULL}, + {2, 503309u, 13668221661727899355ULL}, + {2, 511228u, 8056635900584925629ULL}, + {2, 519147u, 2371813117170145389ULL}, + {2, 527066u, 11631430866345469306ULL}, + {2, 534985u, 3391000685292444630ULL}, + {2, 542904u, 1748974867776887855ULL}, + {2, 550823u, 12245671744384124113ULL}, + {2, 558742u, 14093335007620427588ULL}, + {2, 566661u, 1834971198173119818ULL}, + {2, 574580u, 11489914551042742038ULL}, + {2, 582499u, 11144311815646134855ULL}, + {2, 590418u, 6836879586511554304ULL}, + {3, 598337u, 1976035810807648333ULL}, + {3, 606256u, 883352253650328485ULL}, + {3, 614175u, 15160697399241641046ULL}, + {3, 622094u, 18205160147392533888ULL}, + {3, 630013u, 14713795521886969930ULL}, + {3, 637932u, 11922145548072268503ULL}, + {3, 645851u, 7792075245259396222ULL}, + {3, 653770u, 8258093120125759069ULL}, + {3, 661689u, 18415915043351740624ULL}, + {3, 669608u, 6976820877669932813ULL}, + {3, 677527u, 11393741950045336747ULL}, + {3, 685446u, 7013445700322398ULL}, + {3, 693365u, 16301890081953396848ULL}, + {3, 701284u, 2884016264197242965ULL}, + {3, 709203u, 13109705519595437632ULL}, + {3, 717122u, 9038234598152107521ULL}, + {3, 725041u, 18120218201080976346ULL}, + {3, 732960u, 16154636395797325481ULL}, + {3, 740879u, 11006938371435845325ULL}, + {3, 748798u, 5101920956829682532ULL}, + {3, 756717u, 8748102682002764481ULL}, + {3, 764636u, 11659063084790268686ULL}, + {3, 772555u, 2655796341723522167ULL}, + {3, 780474u, 725836304033682059ULL}, + {4, 788393u, 17319385156311552112ULL}, + {4, 796312u, 16114144959221699025ULL}, + {4, 804231u, 10340858242751730055ULL}, + {4, 812150u, 16019673527993767970ULL}, + {4, 820069u, 9428795686763808470ULL}, + {4, 827988u, 11071396149133517701ULL}, + {4, 835907u, 3234787090869658245ULL}, + {4, 843826u, 12935715497379451815ULL}, + {4, 851745u, 9458909090346731205ULL}, + {4, 859664u, 13671555177889190665ULL}, + {4, 867583u, 15378978062566025315ULL}, + {4, 875502u, 6874713299200778180ULL}, + {4, 883421u, 2952795751253253804ULL}, + {4, 891340u, 840002272274625432ULL}, + {4, 899259u, 2080632909900450398ULL}, + {4, 907178u, 8985056800710389501ULL}, + {4, 915097u, 9639344470705128394ULL}, + {4, 923016u, 16503286310499537632ULL}, + {4, 930935u, 6516524042821633501ULL}, + {4, 938854u, 13680118317128312181ULL}, + {4, 946773u, 3895685521886869962ULL}, + {4, 954692u, 10075103390259047234ULL}, + {4, 962611u, 7659016989448857716ULL}, + {4, 970530u, 16226987279403785379ULL}, + {5, 978449u, 7288319002546285772ULL}, + {5, 986368u, 17612033881854792519ULL}, + {5, 994287u, 3461599239973342401ULL}, + {5, 1002206u, 15039810666827916584ULL}, + {5, 1010125u, 18371164988567740942ULL}, + {5, 1018044u, 12293430003845797862ULL}, + {5, 1025963u, 8102361577346857935ULL}, + {5, 1033882u, 2564456440406630395ULL}, + {5, 1041801u, 3483474835034988953ULL}, + {5, 1049720u, 2501774471487365128ULL}, + {5, 1057639u, 16938717331603262696ULL}, + {5, 1065558u, 6788858469973355994ULL}, + {5, 1073477u, 4916021252031669732ULL}, + {5, 1081396u, 3311612869175857256ULL}, + {5, 1089315u, 1257421795503950132ULL}, + {5, 1097234u, 13091701898044066741ULL}, + {5, 1105153u, 658427270734594543ULL}, + {5, 1113072u, 5468683957858687788ULL}, + {5, 1120991u, 14975481465617277333ULL}, + {5, 1128910u, 18275530173698096306ULL}, + {5, 1136829u, 5749156747542087814ULL}, + {5, 1144748u, 4516671183284595814ULL}, + {5, 1152667u, 12988872537847733407ULL}, + {5, 1160586u, 4971511207443437606ULL}, +}; + +static int const VoxelGoldenCaseCount = 144; From f6cb438d4285e5bdc3ee1fa22bf676782ca2f4a8 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:57:31 +0200 Subject: [PATCH 02/14] Resolve the merge conflict left in the unshaded voxel drawers --- code/voxlib.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/code/voxlib.cpp b/code/voxlib.cpp index 895c50c9..d143ba3b 100644 --- a/code/voxlib.cpp +++ b/code/voxlib.cpp @@ -1964,16 +1964,9 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr++; -<<<<<<< HEAD - /// Compute buffer index and write color - unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); - VoxelDrawBuffer[buffer_index] = color_index; - VoxelDrawBuffer[buffer_index + 1] = color_index; -======= /// Compute buffer index and write color. Unlike the shaded /// drawers, this one covers a single buffer byte per voxel. VoxelDrawBuffer[(pixel_x >> 8) | (pixel_y & 0xFF00)] = color_index; ->>>>>>> 0fef683 (Translate voxel drawing and colour operations to C++) pixel_x += state->TransformMatrix[3].I; pixel_y += state->TransformMatrix[3].J; @@ -2051,16 +2044,9 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr--; -<<<<<<< HEAD - /// Compute buffer index and write color - unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); - VoxelDrawBuffer[buffer_index] = color_index; - VoxelDrawBuffer[buffer_index + 1] = color_index; -======= /// Compute buffer index and write color. Unlike the shaded /// drawers, this one covers a single buffer byte per voxel. VoxelDrawBuffer[(pixel_x >> 8) | (pixel_y & 0xFF00)] = color_index; ->>>>>>> 0fef683 (Translate voxel drawing and colour operations to C++) pixel_x += state->TransformMatrix[3].I; pixel_y += state->TransformMatrix[3].J; From 710868fe6eace9608936e28430bcf167787e6f11 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:58:00 +0200 Subject: [PATCH 03/14] Remove the assembly superseded by the C++ colour and voxel ports --- code/winasm.asm | 2538 ----------------------------------------------- 1 file changed, 2538 deletions(-) delete mode 100644 code/winasm.asm diff --git a/code/winasm.asm b/code/winasm.asm deleted file mode 100644 index f02ccaed..00000000 --- a/code/winasm.asm +++ /dev/null @@ -1,2538 +0,0 @@ -;****************************************************************************** -;* O P E N T S -;****************************************************************************** -;* SPDX-License-Identifier: GPL-3.0-or-later -;* Copyright 2025 Electronic Arts Inc. -;* Copyright 2026 OpenTS contributors -;* -;* Contains material derived from Electronic Arts source code. -;* Modified by OpenTS contributors, 2026. -;* EA's GPLv3 Section 7 additional terms and supplemental warranty -;* disclaimers apply; see LICENSE.md. -;****************************************************************************** - -;*************************************************************************** -;** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S I N C ** -;*************************************************************************** -;* * -;* Project Name : Command & Conquer * -;* * -;* File Name : WINSAM.ASM * -;* * -;* Programmer : Steve Tall * -;* * -;* Start Date : October 26th, 1995 * -;* * -;* Last Update : October 26th, 1995 [ST] * -;* * -;*-------------------------------------------------------------------------* -;* Functions: * -;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * - - -;IDEAL -;.386P ;P386 -.686P ; Pentium Pro and above enables CMOV -.mmx -.model flat, C ;MODEL USE32 FLAT - - ; alignment has to be 'page' so that I can use 'align 32' below - _TEXT$mmx segment page public use32 'CODE';codeseg - - -; -; externs -; -EXTERN C VoxelPixelDeltaTable : PTR WORD ; short [256][2] ; Defined in voxlib.cpp -EXTERN C VoxelNormalTranslateTable : BYTE ; uchar [256] ; Defined in voxlib.cpp -EXTERN C VoxelDrawBuffer : BYTE ; uchar [65536] ; Defined in voxdrsys.cpp -EXTERN C VoxelPaletteTranslateTable : BYTE ; uchar [32][256] ; Defined in voxdrsys.cpp -EXTERNDEF C UseCMOV : BYTE -EXTERNDEF C UseMMX : BYTE - - -; no idea how to get this to appear so fake it -_align MACRO count - REPT (count / 8) - ;lea esp, [esp+0] but zero is optimized to a byte.. - db 08Dh, 0A4h, 024h, 00h, 00h, 00h, 00h - ENDM -ENDM - -_align_ MACRO - ;lea esp, [esp+0] but zero is optimized to a byte.. - db 08Dh, 064h, 024h, 00h -ENDM - -_alignm MACRO reg - mov reg,reg -ENDM - - -; -; structs -; -Vector3i16 STRUCT - I SWORD ? - J SWORD ? - K SWORD ? -Vector3i16 ENDS - -IF SIZEOF Vector3i16 NE 6 - ;.ERR - ECHO *** Warning: Vector3i16 is not 6 bytes as expected *** - vecstrucSize DWORD SIZEOF Vector3i16 -ENDIF - - -VoxelFuncArgumentStruct STRUCT ; WARNING: Make sure this struct is updated if the version in voxdrsys.h is modified! - StartOffset DWORD ? ; unsigned char * - EndOffset DWORD ? ; unsigned char * - DataOffset DWORD ? ; unsigned char * - StartIndex SDWORD ? ; int - StrideX SDWORD ? ; int - StrideY SDWORD ? ; int - TransformMatrix Vector3i16 4 DUP (<>) ; Vector3i16[4] - XSize BYTE ? ; unsigned char - YSize BYTE ? ; unsigned char - ZSize BYTE ? ; unsigned char - Padding BYTE ? ; pad to make struct size divisible by 4, matching the C++ implementation layout -VoxelFuncArgumentStruct ENDS - - -IF SIZEOF VoxelFuncArgumentStruct NE 52 - ;.ERR - ECHO *** Warning: VoxelFuncArgumentStruct is not 48 bytes as expected *** - voxstrucSize DWORD SIZEOF VoxelFuncArgumentStruct -ENDIF - -TRANSFORM_VECTOR MACRO index:req - EXITM -ENDM - -TRANSFORM_COMPONENT MACRO index:req, component:req - LOCAL offset - IFIDNI , - offset = (Vector3i16.I) - ELSEIFIDNI , - offset = (Vector3i16.J) - ELSEIFIDNI , - offset = (Vector3i16.K) - ELSE - .ERR - ENDIF - - EXITM -ENDM - -ADJUST_COLOR MACRO procname, mode:req - - LOCAL mode - IFIDNI , - - R_POS = 11 - G_POS = 5 - B_POS = 0 - - R_MASK = 11111000b - G_MASK = 11111100b - B_MASK = 11111000b - - R_SHIFT = 8 - G_SHIFT = 3 - B_SHIFT = 3 - - R_SHIFT_MMX = 8 - G_SHIFT_MMX = 5 - B_SHIFT_MMX = 19 - - R_SHIFT_CMOV = 8 - G_SHIFT_CMOV = 13 - B_SHIFT_CMOV = 19 - - ELSEIFIDNI , - - R_POS = 10 - G_POS = 5 - B_POS = 0 - - R_MASK = 11111000b - G_MASK = 11111000b - B_MASK = 11111000b - - R_SHIFT = 7 - G_SHIFT = 2 - B_SHIFT = 3 - - R_SHIFT_MMX = 7 - G_SHIFT_MMX = 6 - B_SHIFT_MMX = 19 - - R_SHIFT_CMOV = 9 - G_SHIFT_CMOV = 14 - B_SHIFT_CMOV = 19 - - ELSEIFIDNI , - - R_POS = 11 - G_POS = 6 - B_POS = 0 - - R_MASK = 11111000b - G_MASK = 11111000b - B_MASK = 11111100b - - R_SHIFT = 8 - G_SHIFT = 3 - B_SHIFT = 2 - - R_SHIFT_MMX = 8 - G_SHIFT_MMX = 5 - B_SHIFT_MMX = 18 - - R_SHIFT_CMOV = 8 - G_SHIFT_CMOV = 13 - B_SHIFT_CMOV = 18 - - ELSEIFIDNI , - - R_POS = 11 - G_POS = 5 - B_POS = 0 - - R_MASK = 11111100b - G_MASK = 11111000b - B_MASK = 11111000b - - R_SHIFT = 8 - G_SHIFT = 2 - B_SHIFT = 3 - - R_SHIFT_MMX = 8 - G_SHIFT_MMX = 6 - B_SHIFT_MMX = 19 - - R_SHIFT_CMOV = 8 - G_SHIFT_CMOV = 14 - B_SHIFT_CMOV = 19 - - ELSE - .ERR - ENDIF -PUBLIC C &procname - -&procname proc C uses ebx ecx edx esi edi, \ - srcpal:DWORD, \ - dstpal:DWORD, \ - red:DWORD, \ - green:DWORD, \ - blue:DWORD, \ - intensity:DWORD, \ - _mask:DWORD - - LOCAL value:DWORD - LOCAL counter:DWORD - - cmp UseMMX, 0 - jnz ??mmx_path - - cmp UseCMOV, 0 - jnz ??cmov_path - - mov [counter], 255 - mov esi, [srcpal] - mov edi, [dstpal] - mov edx, [_mask] - - ; skip first index which is transparent - add esi, 3 - ; skip first mask index - inc edx - - mov word ptr [edi], 0 - xor ebx, ebx - jmp ??regular_loop - -??cmov_path: - pushfd - cld - - mov [counter], 255 - mov esi, [srcpal] - mov [value], 000FF0000h - mov edi, [dstpal] - mov edx, [_mask] - - ; skip first index which is transparent - add esi, 3 - ; skip first mask index - inc edx - - mov word ptr [edi], 0 - - ; advance destination - add edi, 2 - - jmp ??cmov_loop - -??mmx_path: - mov [counter], 255 - mov esi, [srcpal] - mov edi, [dstpal] - mov edx, [_mask] - - ; skip first index which is transparent - add esi, 3 - ; skip first mask index - inc edx - - sub edi, 2 - - movq mm1, qword ptr [red] - movq mm2, qword ptr [blue] - psrad mm1, 4 - psrad mm2, 4 - packssdw mm1, mm2 - pxor mm0, mm0 - movq mm2, mm1 - punpckhwd mm2, mm1 - punpckhwd mm2, mm2 - - jmp ??mmx_loop - - align 64 - -??mmx_loop: - ; advance destination - add edi, 2 - - packuswb mm0, mm0 - - ; check mask, if zero use intensity - cmp byte ptr [edx], 0 - jz ??mmx_use_intensity - - movd eax, mm0 - pxor mm0, mm0 - - punpcklbw mm0, [esi] - - mov ebx, eax - - psrlw mm0, 4 - - ; convert to wanted format - and eax, R_MASK - mov ecx, ebx - shl eax, R_SHIFT_MMX - and ebx, (G_MASK * 256) - shr ebx, G_SHIFT_MMX - and ecx, (B_MASK * 256 * 256) - shr ecx, B_SHIFT_MMX - pmulhw mm0, mm1 - - ; combine red and green - or eax, ebx - - ; advance source - add esi, 3 - - or eax, ecx - - ; advance mask - inc edx - - ; store color - mov [edi], ax - - dec [counter] - - jnz ??mmx_loop - -??mmx_exit: - ; advance destination - add edi, 2 - - packuswb mm0, mm0 - - movd eax, mm0 - mov ebx, eax - - ; convert to wanted format - and eax, R_MASK - mov ecx, ebx - shl eax, R_SHIFT_MMX - and ebx, (G_MASK * 256) - shr ebx, G_SHIFT_MMX - and ecx, (B_MASK * 256 * 256) - shr ecx, B_SHIFT_MMX - - ; combine red and green - or eax, ebx - - ; combine blue - or eax, ecx - - ; store color - mov [edi], ax - - emms - ret - -??mmx_use_intensity: - - movd eax, mm0 - pxor mm0, mm0 - - punpcklbw mm0, [esi] - - mov ebx, eax - - psrlw mm0, 4 - - ; convert to wanted format - and eax, R_MASK - mov ecx, ebx - shl eax, R_SHIFT_MMX - and ebx, (G_MASK * 256) - shr ebx, G_SHIFT_MMX - and ecx, (B_MASK * 256 * 256) - shr ecx, B_SHIFT_MMX - - ; scale by intensity - pmulhw mm0, mm2 - - ; combine red and green - or eax, ebx - - ; advance source - add esi, 3 - - ; combine blue - or eax, ecx - - ; advance mask - inc edx - - ; store color - mov [edi], ax - - dec [counter] - - jnz ??mmx_loop - - jmp ??mmx_exit - - align 64 - -??cmov_loop: - ; check mask, if zero use intensity - cmp byte ptr [edx], 0 - - movzx eax, byte ptr [esi] - movzx ebx, byte ptr [esi+1] - movzx ecx, byte ptr [esi+2] - jz ??cmov_use_intensity - - ; scale r g b - imul eax, [red] - imul ebx, [green] - imul ecx, [blue] - -??cmov_inner: - ; advance source - add esi, 3 - - ; clamp r g b - test eax, 0FF000000h - cmovnz eax, [value] - test ebx, 0FF000000h - cmovnz ebx, [value] - test ecx, 0FF000000h - cmovnz ecx, [value] - - ; convert to wanted format - and eax, (R_MASK * 256 * 256) - shr eax, R_SHIFT_CMOV - and ebx, (G_MASK * 256 * 256) - shr ebx, G_SHIFT_CMOV - and ecx, (B_MASK * 256 * 256) - - ; combine red and green - or eax, ebx - - shr ecx, B_SHIFT_CMOV - - ; advance mask - inc edx - - ; combine blue - or eax, ecx - - ; store color - stosw - - dec [counter] - - jnz ??cmov_loop - - popfd - - ret - -??cmov_use_intensity: - imul eax, [intensity] - imul ebx, [intensity] - imul ecx, [intensity] - jmp ??cmov_inner - - align 64 - -??regular_loop: - xor eax, eax - mov bl, [esi+1] - xor ecx, ecx - mov al, [esi] - - ; check mask, if zero use intensity - cmp byte ptr [edx], 0 - jz ??regular_use_intensity - - mov cl, [esi+2] - inc edx - imul eax, [red] - imul ebx, [green] - imul ecx, [blue] - - shr eax, 16 - - ; advance source - add esi, 3 - - shr ebx, 16 - - ; clamp r g b - cmp eax, 255 - setbe ah - shr ecx, 16 - dec ah - or al, ah - cmp ebx, 255 - setbe bh - dec bh - cmp ecx, 255 - setbe ch - or bl, bh - dec ch - or cl, ch - - ; convert to wanted format - and eax, R_MASK - shl eax, R_SHIFT - and ebx, G_MASK - shl ebx, G_SHIFT - and ecx, B_MASK - shr ecx, B_SHIFT - - ; combine red and green - or eax, ebx - - ; advance destination - add edi, 2 - - xor ebx, ebx - - ; combine blue - or eax, ecx - - dec [counter] - - ; store color - mov [edi], ax - - jnz ??regular_loop - - ret - -??regular_use_intensity: - - mov cl, [esi+2] - - ; advance mask - inc edx - - ; increase color by intensity - imul eax, [intensity] - imul ebx, [intensity] - imul ecx, [intensity] - - ; normalize red - shr eax, 16 - - ; advance source - add esi, 3 - - ; normalize green - shr ebx, 16 - - ; clamp r g b - cmp eax, 255 - setbe ah - shr ecx, 16 - dec ah - or al, ah - cmp ebx, 255 - setbe bh - dec bh - cmp ecx, 255 - setbe ch - or bl, bh - dec ch - or cl, ch - - ; convert to wanted format - and eax, R_MASK - shl eax, R_SHIFT - and ebx, G_MASK - shl ebx, G_SHIFT - and ecx, B_MASK - shr ecx, B_SHIFT - - ; combine red and green - or eax, ebx - - ; advance destination - add edi, 2 - - xor ebx, ebx - - ; combine blue - or eax, ecx - - dec [counter] - - ; store color - mov [edi], ax - - jnz ??regular_loop - - ret -&procname ENDP -ENDM - -ADJUST_COLOR Adjust_Color_565, rgb565 -ADJUST_COLOR Adjust_Color_555, rgb555 -ADJUST_COLOR Adjust_Color_556, rgb556 -ADJUST_COLOR Adjust_Color_655, rgb655 - - -BRIGHTEN_COLOR MACRO procname, mode:req - - LOCAL mode - IFIDNI , - - CONSTANT_0 = 8 - CONSTANT_1 = 3 - CONSTANT_2 = 0F8h - CONSTANT_3 = 0FCh - CONSTANT_4 = 8 - CONSTANT_5 = 8 - CONSTANT_6 = 3 - CONSTANT_7 = 2 - CONSTANT_8 = 11 - CONSTANT_9 = 5 - CONSTANT_10 = 3 - CONSTANT_11 = 8 - CONSTANT_12 = 3 - - ELSEIFIDNI , - - CONSTANT_0 = 8 - CONSTANT_1 = 2 - CONSTANT_2 = 0FCh - CONSTANT_3 = 0F8h - CONSTANT_4 = 8 - CONSTANT_5 = 8 - CONSTANT_6 = 2 - CONSTANT_7 = 3 - CONSTANT_8 = 10 - CONSTANT_9 = 5 - CONSTANT_10 = 3 - CONSTANT_11 = 8 - CONSTANT_12 = 3 - - ELSEIFIDNI , - - CONSTANT_0 = 8 - CONSTANT_1 = 3 - CONSTANT_2 = 0F8h - CONSTANT_3 = 0F8h - CONSTANT_4 = 8 - CONSTANT_5 = 8 - CONSTANT_6 = 3 - CONSTANT_7 = 3 - CONSTANT_8 = 11 - CONSTANT_9 = 6 - CONSTANT_10 = 2 - CONSTANT_11 = 8 - CONSTANT_12 = 2 - - ELSEIFIDNI , - - CONSTANT_0 = 7 - CONSTANT_1 = 2 - CONSTANT_2 = 0F8h - CONSTANT_3 = 0F8h - CONSTANT_4 = 8 - CONSTANT_5 = 8 - CONSTANT_6 = 3 - CONSTANT_7 = 3 - CONSTANT_8 = 10 - CONSTANT_9 = 5 - CONSTANT_10 = 3 - CONSTANT_11 = 8 - CONSTANT_12 = 3 - - ELSE - .ERR - ENDIF -PUBLIC C &procname - -&procname proc C uses ebx ecx edx esi edi, \ - mul_buffer:DWORD, \ - color_buffer:DWORD, \ - mulbuff_width:DWORD, \ - color_buff_width:DWORD, \ - dst_width:DWORD, \ - dst_height:DWORD - - LOCAL wleft:DWORD - LOCAL hleft:DWORD - LOCAL local4:DWORD - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - xor eax, eax - mov [local2], eax - mov eax, [dst_height] - mov [hleft], eax - mov [local1], 0 - mov esi, [mul_buffer] - mov [local4], esi - mov edi, [color_buffer] - mov [local3], edi - -??loop1: - mov eax, [dst_width] - mov [wleft], eax - xor eax, eax - xor ebx, ebx - -??loop2: - mov al, [esi] - test al, al - jz ??inc - - mov bx, [edi] - mov byte ptr [local1], al - mov [local2], ebx - shr ebx, CONSTANT_0 - mov eax, dword ptr [local2] - shr eax, CONSTANT_1 - and ebx, CONSTANT_2 - and eax, CONSTANT_3 - mov edx, ebx - mov ecx, eax - imul ebx, [local1] - imul eax, [local1] - shr ebx, CONSTANT_4 - shr eax, CONSTANT_5 - add bl, dl - setnb dl - add al, cl - setnb cl - dec dl - dec cl - or bl, dl - or al, cl - shr ebx, CONSTANT_6 - shr eax, CONSTANT_7 - shl ebx, CONSTANT_8 - shl eax, CONSTANT_9 - mov ecx, [local2] - shl ecx, CONSTANT_10 - or eax, ebx - and ecx, 0FFh - mov edx, ecx - imul ecx, [local1] - shr ecx, CONSTANT_11 - add cl, dl - setnb dl - dec dl - or cl, dl - shr ecx, CONSTANT_12 - or eax, ecx - mov [edi], ax - -??inc: - inc esi - add edi, 2 - dec [wleft] - jnz ??loop2 - - mov esi, [local4] - add esi, [mulbuff_width] - mov [local4], esi - mov edi, [local3] - add edi, [color_buff_width] - mov [local3], edi - dec [hleft] - jnz ??loop1 - - ret - -&procname ENDP -ENDM - -BRIGHTEN_COLOR Brighten_Color_565, rgb565 -BRIGHTEN_COLOR Brighten_Color_655, rgb655 - -BRIGHTEN_COLOR Brighten_Color_556, rgb556 -BRIGHTEN_COLOR Brighten_Color_555, rgb555 - -align 128 - -MMX_BRIGHTEN_COLOR MACRO procname, mode:req - - LOCAL mode - IFIDNI , - - CONSTANT_2 = 2 - CONSTANT_3 = 1 - CONSTANT_4 = 5 - CONSTANT_5 = 10 - CONSTANT_6 = 0F8h - - ELSEIFIDNI , - - CONSTANT_2 = 3 - CONSTANT_3 = 0 - CONSTANT_4 = 5 - CONSTANT_5 = 10 - CONSTANT_6 = 07Ch - - ELSEIFIDNI , - - CONSTANT_2 = 2 - CONSTANT_3 = 0 - CONSTANT_4 = 6 - CONSTANT_5 = 10 - CONSTANT_6 = 0F8h - - ELSEIFIDNI , - - CONSTANT_2 = 2 - CONSTANT_3 = 1 - CONSTANT_4 = 4 - CONSTANT_5 = 10 - CONSTANT_6 = 423A0A60h - - ELSE - .ERR - ENDIF -PUBLIC C &procname - -&procname proc C uses ebx ecx edx esi edi, \ - mul_buffer:DWORD, \ - color_buffer:DWORD, \ - mulbuff_width:DWORD, \ - color_buff_width:DWORD, \ - dst_width:DWORD, \ - dst_height:DWORD, \ - mmx_buffer:DWORD - - LOCAL local7:DWORD - LOCAL wleft:DWORD - LOCAL hleft:DWORD - LOCAL local4:DWORD - LOCAL local3:DWORD - LOCAL local2:QWORD - LOCAL local1:QWORD - - xor eax, eax - mov [local3], eax - mov eax, [dst_height] - mov [wleft], eax - mov dword ptr [local2], 0 - mov dword ptr [local2+4], 0 - mov dword ptr [local1], 0 - mov dword ptr [local1+4], 0 - mov esi, [mul_buffer] - mov [hleft], esi - mov edi, [color_buffer] - mov [local4], edi - mov edx, [mmx_buffer] - -??loc_6C8BC1: - mov eax, [dst_width] - mov [local7], eax - xor eax, eax - xor ebx, ebx - jmp short ??loc_6C8C40 - - align 64 - -??loc_6C8C00: - inc esi - lea edi, [edi+2] - dec [local7] - jnz ??loc_6C8C40 - - mov esi, [hleft] - add esi, [mulbuff_width] - mov [hleft], esi - mov edi, [local4] - add edi, [color_buff_width] - mov [local4], edi - dec [wleft] - jnz ??loc_6C8BC1 - - jmp ??loc_6C8CB7 - - align 64 - -??loc_6C8C40: - mov al, [esi] - test al, al - jz ??loc_6C8C00 - - mov byte ptr [local2], al - mov bx, [edi] - mov byte ptr [local2+2], al - mov byte ptr [local2+4], al - punpcklbw mm0, [edx+ebx*4] - psrlw mm0, 8 - movq mm1, mm0 - pmullw mm0, [local2] - psrlw mm0, 8 - paddusb mm0, mm1 - psrlw mm0, CONSTANT_2 - movq [local1], mm0 - - xor ebx, ebx - xor eax, eax - mov bl, byte ptr [local1] - mov al, byte ptr [local1+2] - -if CONSTANT_3 gt 0 - shr bl, CONSTANT_3 -endif - - xor ecx, ecx - shl eax, CONSTANT_4 - mov cl, byte ptr [local1+4] - shl ecx, CONSTANT_5 -if CONSTANT_6 eq 0423A0A60h - and eax, CONSTANT_6 - or ebx, eax -else - or ebx, eax - and ecx, (CONSTANT_6 * 256) -endif - inc esi - or ebx, ecx - lea edi, [edi+2] - mov [edi-2], bx - dec [local7] - jnz ??loc_6C8C40 - - mov esi, [hleft] - add esi, [mulbuff_width] - mov [hleft], esi - mov edi, [local4] - add edi, [color_buff_width] - mov [local4], edi - dec [wleft] - jnz ??loc_6C8BC1 - -??loc_6C8CB7: - emms - ret - -&procname ENDP -ENDM - - -MMX_BRIGHTEN_COLOR MMX_Brighten_Color_565, rgb565 -MMX_BRIGHTEN_COLOR MMX_Brighten_Color_555, rgb555 -MMX_BRIGHTEN_COLOR MMX_Brighten_Color_556, rgb556 -MMX_BRIGHTEN_COLOR MMX_Brighten_Color_655, rgb655 - -align 8 - -; VOID cdecl Func(VoxelFuncArgumentStruct * arg1); -Draw_Voxel_Regular_Normals_ASM proc C uses esi edi ebx ecx edx \ - arg1:DWORD - - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - assume esi:ptr VoxelFuncArgumentStruct - - mov esi, arg1 - push ebp - movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] - xor ecx, ecx - mov cl, [esi].ZSize - mov edi, offset VoxelPixelDeltaTable - xor eax, eax - xor ebx, ebx - mov esi, 4 - -??loc_6C8E6A: - mov [edi], ax - add edi, 2 - add eax, ebp - mov [edi], bx - add edi, 2 - add ebx, edx - dec ecx - jnz ??loc_6C8E6A - - pop ebp - mov esi, arg1 - xor eax, eax - mov eax, [esi + TRANSFORM_VECTOR(0)] - mov local1, eax - mov ch, [esi].YSize - -??loc_6C8E8C: - mov eax, [esi].StartIndex - mov local3, eax - mov eax, local1 - mov local2, eax - mov cl, [esi].XSize - -??loc_6C8E9B: - mov eax, local1 - mov [esi + TRANSFORM_VECTOR(0)], eax - xor edi, edi - mov eax, [esi].StartIndex - mov ebx, [esi].StartOffset - or edi, [ebx + eax*4] - jns ??loc_6C8EE0 - -??loc_6C8EAD: - mov eax, [esi + TRANSFORM_VECTOR(1)] - add local1, eax - mov eax, [esi].StrideX - add [esi].StartIndex, eax - dec cl - jnz ??loc_6C8E9B - - mov eax, local2 - add eax, [esi + TRANSFORM_VECTOR(2)] - mov local1, eax - mov eax, local3 - add eax, [esi].StrideY - mov [esi].StartIndex, eax - dec ch - jnz ??loc_6C8E8C - - ret - - align 8 - -??loc_6C8EE0: - push esi - push ecx - push ebp - xor ecx, ecx - add edi, [esi].DataOffset - mov cl, [esi].ZSize - mov bx, [esi + TRANSFORM_COMPONENT(0,J)] - shl ebx, 16 - mov ebp, [esi + TRANSFORM_VECTOR(3)] - mov bx, [esi + TRANSFORM_COMPONENT(0,I)] - -??loc_6C8EF9: - xor eax, eax - cmp ecx, 0 - jz ??loc_6C8F36 - - mov al, [edi] - inc edi - sub cl, al - - add ebx, [VoxelPixelDeltaTable + eax*4] - mov ch, [edi] - inc edi - test ch, ch - jz ??loc_6C8F33 - -??loc_6C8F13: - mov eax, ebx - dec cl - shr eax, 16 - mov dl, [edi] - mov al, bh - add edi, 2 - add ebx, ebp - dec ch - mov [VoxelDrawBuffer + eax], dl - mov [VoxelDrawBuffer + eax + 1], dl - jnz ??loc_6C8F13 - -??loc_6C8F33: - inc edi - jmp ??loc_6C8EF9 - -??loc_6C8F36: - pop ebp - pop ecx - pop esi - jmp ??loc_6C8EAD - -Draw_Voxel_Regular_Normals_ASM endp - -align 8 - -; VOID cdecl Func(VoxelFuncArgumentStruct * arg1); -Draw_Voxel_Reverse_Normals_ASM proc C uses esi edi ebx ecx edx \ - arg1:DWORD - - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - assume eax:ptr VoxelFuncArgumentStruct - - mov esi, arg1 - push ebp - movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] - xor ecx, ecx - mov cl, [esi].ZSize - mov edi, offset VoxelPixelDeltaTable - xor eax, eax - xor ebx, ebx - mov esi, 4 - -??loc_6C8F6A: - mov [edi], ax - add edi, 2 - add eax, ebp - mov [edi], bx - add edi, 2 - add ebx, edx - dec ecx - jnz ??loc_6C8F6A - - pop ebp - mov esi, arg1 - xor eax, eax - mov eax, [esi + TRANSFORM_VECTOR(0)] - mov local1, eax - mov ch, [esi].YSize - -??loc_6C8F8C: - mov eax, [esi].StartIndex - mov local3, eax - mov eax, local1 - mov local2, eax - mov cl, [esi].XSize - -??loc_6C8F9B: - mov eax, local1 - mov [esi + TRANSFORM_VECTOR(0)], eax - xor edi, edi - mov eax, [esi].StartIndex - mov ebx, [esi].EndOffset - or edi, [ebx + eax*4] - jns ??loc_6C8FE0 - -??loc_6C8FAE: - mov eax, [esi + TRANSFORM_VECTOR(1)] - add local1, eax - mov eax, [esi].StrideX - add [esi].StartIndex, eax - dec cl - jnz ??loc_6C8F9B - - mov eax, local2 - add eax, [esi + TRANSFORM_VECTOR(2)] - mov local1, eax - mov eax, local3 - add eax, [esi].StrideY - mov [esi].StartIndex, eax - dec ch - jnz ??loc_6C8F8C - - ret - - align 8 - -??loc_6C8FE0: - push esi - push ecx - push ebp - xor ecx, ecx - add edi, [esi].DataOffset - mov cl, [esi].ZSize - mov bx, [esi + TRANSFORM_COMPONENT(0,J)] - shl ebx, 16 - mov ebp, [esi + TRANSFORM_VECTOR(3)] - mov bx, [esi + TRANSFORM_COMPONENT(0,I)] - -??loc_6C8FF9: - cmp ecx, 0 - jz ??loc_6C9035 - - mov ch, [edi] - dec edi - test ch, ch - jz ??loc_6C9024 - -??loc_6C9005: - mov eax, ebx - dec cl - dec edi - shr eax, 16 - mov dl, [edi] - mov al, bh - dec edi - add ebx, ebp - dec ch - mov [VoxelDrawBuffer + eax], dl - mov [VoxelDrawBuffer + eax + 1], dl - jnz ??loc_6C9005 - -??loc_6C9024: - dec edi - xor eax, eax - mov al, [edi] - dec edi - sub cl, al - - add ebx, [VoxelPixelDeltaTable + eax*4] - jmp ??loc_6C8FF9 - -??loc_6C9035: - pop ebp - pop ecx - pop esi - jmp ??loc_6C8FAE - -Draw_Voxel_Reverse_Normals_ASM endp - -align 8 - -; VOID cdecl Func(VoxelFuncArgumentStruct * arg1); -Draw_Voxel_Regular_Lighting_Normals_ASM proc C uses esi edi ebx ecx edx \ - arg1:DWORD - - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - assume eax:ptr VoxelFuncArgumentStruct - - mov esi, arg1 - push ebp - movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] - xor ecx, ecx - mov cl, [esi].ZSize - mov edi, offset VoxelPixelDeltaTable - xor eax, eax - xor ebx, ebx - mov esi, 4 - -??loc_6C906A: - mov [edi], ax - add edi, 2 - add eax, ebp - mov [edi], bx - add edi, 2 - add ebx, edx - dec ecx - jnz ??loc_6C906A - - pop ebp - mov esi, arg1 - xor eax, eax - mov eax, [esi + TRANSFORM_VECTOR(0)] - mov local1, eax - mov ch, [esi].YSize - -??loc_6C908C: - mov eax, [esi].StartIndex - mov local3, eax - mov eax, local1 - mov local2, eax - mov cl, [esi].XSize - -??loc_6C909B: - mov eax, local1 - mov [esi + TRANSFORM_VECTOR(0)], eax - xor edi, edi - mov eax, [esi].StartIndex - mov ebx, [esi].StartOffset - or edi, [ebx + eax*4] - jns ??loc_6C90E0 - -??loc_6C90AD: - mov eax, [esi + TRANSFORM_VECTOR(1)] - add local1, eax - mov eax, [esi].StrideX - add [esi].StartIndex, eax - dec cl - jnz ??loc_6C909B - - mov eax, local2 - add eax, [esi + TRANSFORM_VECTOR(2)] - mov local1, eax - mov eax, local3 - add eax, [esi].StrideY - mov [esi].StartIndex, eax - dec ch - jnz ??loc_6C908C - - ret - - align 8 - -??loc_6C90E0: - push esi - push ecx - push ebp - xor ecx, ecx - add edi, [esi].DataOffset - mov cl, [esi].ZSize - mov bx, [esi + TRANSFORM_COMPONENT(0,J)] - shl ebx, 16 - mov ebp, [esi + TRANSFORM_VECTOR(3)] - mov bx, [esi + TRANSFORM_COMPONENT(0,I)] - -??loc_6C90F9: - xor eax, eax - cmp ecx, 0 - jz ??loc_6C9147 - - mov al, [edi] - inc edi - sub cl, al - - add ebx, [VoxelPixelDeltaTable + eax*4] - mov ch, [edi] - inc edi - test ch, ch - jz ??loc_6C9144 - -??loc_6C9113: - mov eax, ebx - dec cl - shr eax, 16 - xor edx, edx - mov dl, [edi+1] - mov al, bh - mov dh, VoxelNormalTranslateTable[edx] - mov dl, [edi] - add ebx, ebp - add edi, 2 - dec ch - mov dl, VoxelPaletteTranslateTable[edx] - mov [VoxelDrawBuffer + eax], dl - mov [VoxelDrawBuffer + eax + 1], dl - jnz ??loc_6C9113 - -??loc_6C9144: - inc edi - jmp ??loc_6C90F9 - -??loc_6C9147: - pop ebp - pop ecx - pop esi - jmp ??loc_6C90AD - -Draw_Voxel_Regular_Lighting_Normals_ASM endp - -align 8 - -; VOID cdecl Func(VoxelFuncArgumentStruct * arg1); -Draw_Voxel_Reverse_Lighting_Normals_ASM proc C uses esi edi ebx ecx edx \ - arg1:DWORD - - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - assume eax:ptr VoxelFuncArgumentStruct - - mov esi, arg1 - push ebp - movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] - xor ecx, ecx - mov cl, [esi].ZSize - mov edi, offset VoxelPixelDeltaTable - xor eax, eax - xor ebx, ebx - mov esi, 4 - -??loc_6C918A: - mov [edi], ax - add edi, 2 - add eax, ebp - mov [edi], bx - add edi, 2 - add ebx, edx - dec ecx - jnz ??loc_6C918A - - pop ebp - mov esi, arg1 - xor eax, eax - mov eax, [esi + TRANSFORM_VECTOR(0)] - mov local1, eax - mov ch, [esi].YSize - -??loc_6C91AC: - mov eax, [esi].StartIndex - mov local3, eax - mov eax, local1 - mov local2, eax - mov cl, [esi].XSize - -??loc_6C91BB: - mov eax, local1 - mov [esi + TRANSFORM_VECTOR(0)], eax - xor edi, edi - mov eax, [esi].StartIndex - mov ebx, [esi].EndOffset - or edi, [ebx + eax*4] - jns ??loc_6C9200 - -??loc_6C91CE: - mov eax, [esi + TRANSFORM_VECTOR(1)] - add local1, eax - mov eax, [esi].StrideX - add [esi].StartIndex, eax - dec cl - jnz ??loc_6C91BB - - mov eax, local2 - add eax, [esi + TRANSFORM_VECTOR(2)] - mov local1, eax - mov eax, local3 - add eax, [esi].StrideY - mov [esi].StartIndex, eax - dec ch - jnz ??loc_6C91AC - - ret - - align 8 - -??loc_6C9200: - push esi - push ecx - push ebp - xor ecx, ecx - add edi, [esi].DataOffset - mov cl, [esi].ZSize - mov bx, [esi + TRANSFORM_COMPONENT(0,J)] - shl ebx, 16 - mov ebp, [esi + TRANSFORM_VECTOR(3)] - mov bx, [esi + TRANSFORM_COMPONENT(0,I)] - -??loc_6C9219: - cmp ecx, 0 - jz ??loc_6C9267 - - mov ch, [edi] - dec edi - test ch, ch - jz ??loc_6C9256 - -??loc_6C9225: - mov eax, ebx - dec cl - shr eax, 16 - xor edx, edx - mov dl, [edi] - mov al, bh - mov dh, VoxelNormalTranslateTable[edx] - mov dl, [edi-1] - add ebx, ebp - sub edi, 2 - dec ch - mov dl, VoxelPaletteTranslateTable[edx] - mov [VoxelDrawBuffer + eax], dl - mov [VoxelDrawBuffer + eax + 1], dl - jnz ??loc_6C9225 - -??loc_6C9256: - dec edi - xor eax, eax - mov al, [edi] - dec edi - sub cl, al - - add ebx, [VoxelPixelDeltaTable + eax*4] - jmp ??loc_6C9219 - -??loc_6C9267: - pop ebp - pop ecx - pop esi - jmp ??loc_6C91CE - -Draw_Voxel_Reverse_Lighting_Normals_ASM endp - -align 8 - -; VOID cdecl Func(VoxelFuncArgumentStruct * arg1); -Draw_Voxel_Regular_ASM proc C uses esi edi ebx ecx edx \ - arg1:DWORD - - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - assume eax:ptr VoxelFuncArgumentStruct - - mov esi, arg1 - push ebp - movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] - mov ecx, 0FFh - sub cl, [esi].ZSize - mov edi, offset VoxelPixelDeltaTable - xor eax, eax - xor ebx, ebx - mov esi, 4 - -??loc_6C92AD: - mov [edi], ax - add edi, 2 - add eax, ebp - mov [edi], bx - add edi, 2 - add ebx, edx - dec ecx - jnz ??loc_6C92AD - - pop ebp - mov esi, arg1 - xor eax, eax - mov eax, [esi + TRANSFORM_VECTOR(0)] - mov local1, eax - mov ch, [esi].YSize - -??loc_6C92CF: - mov eax, [esi].StartIndex - mov local3, eax - mov eax, local1 - mov local2, eax - mov cl, [esi].XSize - -??loc_6C92DE: - mov eax, local1 - mov [esi + TRANSFORM_VECTOR(0)], eax - xor edi, edi - mov eax, [esi].StartIndex - mov ebx, [esi].StartOffset - or edi, [ebx + eax*4] - jns ??loc_6C9320 - -??loc_6C92F0: - mov eax, [esi + TRANSFORM_VECTOR(1)] - add local1, eax - mov eax, [esi].StrideX - add [esi].StartIndex, eax - dec cl - jnz ??loc_6C92DE - - mov eax, local2 - add eax, [esi + TRANSFORM_VECTOR(2)] - mov local1, eax - mov eax, local3 - add eax, [esi].StrideY - mov [esi].StartIndex, eax - dec ch - jnz ??loc_6C92CF - - ret - - align 8 - -??loc_6C9320: - push esi - push ecx - push ebp - xor ecx, ecx - add edi, [esi].DataOffset - mov cl, [esi].ZSize - mov bx, [esi + TRANSFORM_COMPONENT(0,J)] - shl ebx, 16 - mov ebp, [esi + TRANSFORM_VECTOR(3)] - mov bx, [esi + TRANSFORM_COMPONENT(0,I)] - -??loc_6C9339: - xor eax, eax - cmp ecx, 0 - jz ??loc_6C936E - - mov al, [edi] - inc edi - sub cl, al - - add ebx, [VoxelPixelDeltaTable + eax*4] - mov ch, [edi] - inc edi - test ch, ch - jz ??loc_6C936B - -??loc_6C9353: - mov eax, ebx - dec cl - shr eax, 16 - mov dl, [edi] - mov al, bh - inc edi - add ebx, ebp - dec ch - mov [VoxelDrawBuffer + eax], dl - jnz ??loc_6C9353 - -??loc_6C936B: - inc edi - jmp ??loc_6C9339 - -??loc_6C936E: - pop ebp - pop ecx - pop esi - jmp ??loc_6C92F0 - -Draw_Voxel_Regular_ASM endp - -align 8 - -; VOID cdecl Func(VoxelFuncArgumentStruct * arg1); -Draw_Voxel_Reverse_ASM proc C uses esi edi ebx ecx edx \ - arg1:DWORD - - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - assume eax:ptr VoxelFuncArgumentStruct - - mov esi, arg1 - push ebp - movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] - mov ecx, 0FFh - sub cl, [esi].ZSize - mov edi, offset VoxelPixelDeltaTable - xor eax, eax - xor ebx, ebx - mov esi, 4 - -??loc_6C93AD: - mov [edi], ax - add edi, 2 - add eax, ebp - mov [edi], bx - add edi, 2 - add ebx, edx - dec ecx - jnz ??loc_6C93AD - - pop ebp - mov esi, arg1 - xor eax, eax - mov eax, [esi + TRANSFORM_VECTOR(0)] - mov local1, eax - mov ch, [esi].YSize - -??loc_6C93CF: - mov eax, [esi].StartIndex - mov local3, eax - mov eax, local1 - mov local2, eax - mov cl, [esi].XSize - -??loc_6C93DE: - mov eax, local1 - mov [esi + TRANSFORM_VECTOR(0)], eax - xor edi, edi - mov eax, [esi].StartIndex - mov ebx, [esi].EndOffset - or edi, [ebx + eax*4] - jns ??loc_6C9420 - -??loc_6C93F1: - mov eax, [esi + TRANSFORM_VECTOR(1)] - add local1, eax - mov eax, [esi].StrideX - add [esi].StartIndex, eax - dec cl - jnz ??loc_6C93DE - - mov eax, local2 - add eax, [esi + TRANSFORM_VECTOR(2)] - mov local1, eax - mov eax, local3 - add eax, [esi].StrideY - mov [esi].StartIndex, eax - dec ch - jnz ??loc_6C93CF - - ret - - align 8 - -??loc_6C9420: - push esi - push ecx - push ebp - xor ecx, ecx - add edi, [esi].DataOffset - mov cl, [esi].ZSize - mov bx, [esi + TRANSFORM_COMPONENT(0,J)] - shl ebx, 16 - mov ebp, [esi + TRANSFORM_VECTOR(3)] - mov bx, [esi + TRANSFORM_COMPONENT(0,I)] - -??loc_6C9439: - cmp ecx, 0 - jz ??loc_6C946E - - mov ch, [edi] - dec edi - test ch, ch - jz ??loc_6C945D - -??loc_6C9445: - mov eax, ebx - dec cl - shr eax, 16 - mov dl, [edi] - mov al, bh - dec edi - add ebx, ebp - dec ch - mov [VoxelDrawBuffer + eax], dl - jnz ??loc_6C9445 - -??loc_6C945D: - dec edi - xor eax, eax - mov al, [edi] - dec edi - sub cl, al - - add ebx, [VoxelPixelDeltaTable + eax*4] - jmp ??loc_6C9439 - -??loc_6C946E: - pop ebp - pop ecx - pop esi - jmp ??loc_6C93F1 - -Draw_Voxel_Reverse_ASM endp - -align 8 - -; VOID cdecl Func(VoxelFuncArgumentStruct * arg1); -Draw_Voxel_Regular_UNUSED_ASM proc C uses esi edi ebx ecx edx \ - arg1:DWORD - - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - assume esi:ptr VoxelFuncArgumentStruct - - mov esi, arg1 - push ebp - movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] - mov ecx, 0FFh - sub cl, [esi].ZSize - mov edi, offset VoxelPixelDeltaTable - xor eax, eax - xor ebx, ebx - mov esi, 4 - -??loc_6C94AD: - mov [edi], ax - add edi, 2 - add eax, ebp - mov [edi], bx - add edi, 2 - add ebx, edx - dec ecx - jnz ??loc_6C94AD - - pop ebp - mov esi, arg1 - xor eax, eax - mov eax, [esi + TRANSFORM_VECTOR(0)] - mov local1, eax - mov ch, [esi].YSize - -??loc_6C94CF: - mov eax, [esi].StartIndex - mov local3, eax - mov eax, local1 - mov local2, eax - mov cl, [esi].XSize - -??loc_6C94DE: - mov eax, local1 - mov [esi + TRANSFORM_VECTOR(0)], eax - xor edi, edi - mov eax, [esi].StartIndex - mov ebx, [esi].StartOffset - or edi, [ebx + eax*4] - jns ??loc_6C9520 - -??loc_6C94F0: - mov eax, [esi + TRANSFORM_VECTOR(1)] - add local1, eax - mov eax, [esi].StrideX - add [esi].StartIndex, eax - dec cl - jnz ??loc_6C94DE - - mov eax, local2 - add eax, [esi + TRANSFORM_VECTOR(2)] - mov local1, eax - mov eax, local3 - add eax, [esi].StrideY - mov [esi].StartIndex, eax - dec ch - jnz ??loc_6C94CF - - ret - - align 8 - -??loc_6C9520: - push esi - push ecx - push ebp - xor ecx, ecx - add edi, [esi].DataOffset - mov cl, [esi].ZSize - mov bx, [esi + TRANSFORM_COMPONENT(0,J)] - shl ebx, 16 - mov ebp, [esi + TRANSFORM_VECTOR(3)] - mov bx, [esi + TRANSFORM_COMPONENT(0,I)] - -??loc_6C9539: - xor eax, eax - cmp ecx, 0 - jz ??loc_6C9574 - - mov al, [edi] - inc edi - sub cl, al - - add ebx, [VoxelPixelDeltaTable + eax*4] - mov ch, [edi] - inc edi - test ch, ch - jz ??loc_6C9571 - -??loc_6C9553: - mov eax, ebx - dec cl - shr eax, 16 - mov dl, [edi] - mov al, bh - inc edi - add ebx, ebp - dec ch - mov [VoxelDrawBuffer + eax], dl - mov [VoxelDrawBuffer + eax + 1], dl - jnz ??loc_6C9553 - -??loc_6C9571: - inc edi - jmp ??loc_6C9539 - -??loc_6C9574: - pop ebp - pop ecx - pop esi - jmp ??loc_6C94F0 - -Draw_Voxel_Regular_UNUSED_ASM endp - -align 8 - -; VOID cdecl Func(VoxelFuncArgumentStruct * arg1); -Draw_Voxel_Reverse_UNUSED_ASM proc C uses esi edi ebx ecx edx \ - arg1:DWORD - - LOCAL local3:DWORD - LOCAL local2:DWORD - LOCAL local1:DWORD - - assume esi:ptr VoxelFuncArgumentStruct - - mov esi, arg1 - push ebp - movsx ebp, WORD PTR [esi + TRANSFORM_COMPONENT(3,I)] - movsx edx, WORD PTR [esi + TRANSFORM_COMPONENT(3,J)] - mov ecx, 0FFh - sub cl, [esi].ZSize - mov edi, offset VoxelPixelDeltaTable - xor eax, eax - xor ebx, ebx - mov esi, 4 - -??loc_6C95AD: - mov [edi], ax - add edi, 2 - add eax, ebp - mov [edi], bx - add edi, 2 - add ebx, edx - dec ecx - jnz ??loc_6C95AD - - pop ebp - mov esi, arg1 - xor eax, eax - mov eax, [esi + TRANSFORM_VECTOR(0)] - mov local1, eax - mov ch, [esi].YSize - -??loc_6C95CF: - mov eax, [esi].StartIndex - mov local3, eax - mov eax, local1 - mov local2, eax - mov cl, [esi].XSize - -??loc_6C95DE: - mov eax, local1 - mov [esi + TRANSFORM_VECTOR(0)], eax - xor edi, edi - mov eax, [esi].StartIndex - mov ebx, [esi].EndOffset - or edi, [ebx + eax*4] - jns ??loc_6C9620 - -??loc_6C95F1: - mov eax, [esi + TRANSFORM_VECTOR(1)] - add local1, eax - mov eax, [esi].StrideX - add [esi].StartIndex, eax - dec cl - jnz ??loc_6C95DE - - mov eax, local2 - add eax, [esi + TRANSFORM_VECTOR(2)] - mov local1, eax - mov eax, local3 - add eax, [esi].StrideY - mov [esi].StartIndex, eax - dec ch - jnz ??loc_6C95CF - - ret - - align 8 - -??loc_6C9620: - push esi - push ecx - push ebp - xor ecx, ecx - add edi, [esi].DataOffset - mov cl, [esi].ZSize - mov bx, [esi + TRANSFORM_COMPONENT(0,J)] - shl ebx, 16 - mov ebp, [esi + TRANSFORM_VECTOR(3)] - mov bx, [esi + TRANSFORM_COMPONENT(0,I)] - -??loc_6C9639: - cmp ecx, 0 - jz ??loc_6C9674 - - mov ch, [edi] - dec edi - test ch, ch - jz ??loc_6C9663 - -??loc_6C9645: - mov eax, ebx - dec cl - shr eax, 16 - mov dl, [edi] - mov al, bh - dec edi - add ebx, ebp - dec ch - mov [VoxelDrawBuffer + eax], dl - mov [VoxelDrawBuffer + eax + 1], dl - jnz ??loc_6C9645 - -??loc_6C9663: - dec edi - xor eax, eax - mov al, [edi] - dec edi - sub cl, al - - add ebx, [VoxelPixelDeltaTable + eax*4] - jmp ??loc_6C9639 - -??loc_6C9674: - pop ebp - pop ecx - pop esi - jmp ??loc_6C95F1 - -Draw_Voxel_Reverse_UNUSED_ASM endp - - -public _Int3 -_Int3 proc near - ;int 3 - ret -_Int3 endp - - -;proc Stop_Execution C near -; -; nop -; ret -; -;endp - - - _TEXT$mmx ends - _TEXT$mycode segment page public use32 'CODE' ; segment mycode page public use32 'code' ; Need stricter segment alignment - -public C Asm_Interpolate -public C Asm_Interpolate_Line_Double -public C Asm_Interpolate_Line_Interpolate -extern C PaletteInterpolationTable:byte - - -;********************************************************************************************* -;* Asm_Interpolate -- interpolate a 320x200 buffer to a 640x400 screen * -;* * -;* INPUT: ptr to source buffer (320x200 image) * -;* ptr to dest buffer (640x400) * -;* height of source buffer * -;* width of source buffer * -;* width of dest buffer * -;* * -;* * -;* OUTPUT: none * -;* * -;* Warnings: * -;* * -;* HISTORY: * -;* 12/15/95 ST : Created. * -;*===========================================================================================* - -Asm_Interpolate PROC near USES ebx ecx edi esi \ - \ - , src_ptr:dword \ - , dest_ptr:dword \ - , source_height:dword \ - , source_width:dword \ - , dest_width:dword - - LOCAL old_dest:dword - - pushad - - mov eax,[dest_ptr] - mov [old_dest],eax - - mov esi,[src_ptr] - -??each_line_loop: - mov ecx,[source_width] - sub ecx,2 - shr ecx,1 - mov edi,[old_dest] - jmp ??interpolate_loop - - _align 32 ;align 32 - _alignm edi -; -; convert 2 pixels of source into 4 pixels of destination -; so we can write to video memory with dwords -; -??interpolate_loop: - mov eax,dword ptr [esi] - lea esi,[esi+2] - mov edx,eax - mov ebx,eax - and edx,65535 - ror ebx,8 - mov bl,[edx+PaletteInterpolationTable] - mov bh,ah - and eax,000ffff00h - ror ebx,8 - -;1st 3 pixels now in ebx - - shr eax,8 - mov bh,[eax+PaletteInterpolationTable] - ror ebx,16 - mov [edi],ebx - add edi,4 - - dec ecx - jnz ??interpolate_loop - -; do the last three pixels and a blank on the end of a row - xor eax,eax - mov ax,word ptr [esi] - mov [edi],al - inc edi - lea esi,[esi+2] - mov al,[eax+PaletteInterpolationTable] - mov [edi],al - inc edi - mov [edi],ah - inc edi - mov byte ptr[edi],0 - - mov edi,[dest_width] - add [old_dest],edi - - dec [source_height] - jnz ??each_line_loop - - popad - ret - -Asm_Interpolate endp - - - - - - - - - - - - - - -Asm_Interpolate_Line_Double PROC near \ - , src_ptr:dword \ - , dest_ptr:dword \ - , source_height:dword \ - , source_width:dword \ - , dest_width:dword \ - - LOCAL old_dest:dword - LOCAL width_counter:dword - LOCAL pixel_count:dword - - pushad - - mov eax,[dest_ptr] - mov [old_dest],eax - - mov esi,[src_ptr] - mov edi,[dest_ptr] - -??each_line_loop: - mov [width_counter],0 - mov ecx,[source_width] - sub ecx,2 - shr ecx,1 - mov [pixel_count],ecx - mov ecx,offset LineBuffer - mov edi,[old_dest] - jmp ??interpolate_loop - _align 8 ;align 16 - _align_ - -; convert 2 pixels of source into 4 pixels of destination -??interpolate_loop: - mov eax,dword ptr [esi] - lea esi,[esi+2] - mov edx,eax - mov ebx,eax - and edx,65535 - ror ebx,8 - mov bl,[edx+PaletteInterpolationTable] - mov bh,ah - and eax,000ffff00h - ror ebx,8 - - ;1st 3 pixels now in ebx - shr eax,8 - mov bh,[eax+PaletteInterpolationTable] - ror ebx,16 - mov [edi],ebx - mov [ecx],ebx - add edi,4 - add ecx,4 - - dec [pixel_count] - jnz ??interpolate_loop - -; do the last three pixels and a blank - - xor eax,eax - mov ax,word ptr[esi] - mov [edi],al - mov [ecx],al - inc edi - inc ecx - lea esi,[esi+2] - mov al,[eax+PaletteInterpolationTable] - mov [edi],al - mov [ecx],al - inc edi - inc ecx - mov [edi],ah - mov [ecx],ah - inc edi - inc ecx - mov byte ptr[edi],0 - mov byte ptr[ecx],0 - - mov edi,[dest_width] - shr edi,1 - add [old_dest],edi - push esi - push edi - mov esi,offset LineBuffer - mov edi,[old_dest] - mov ecx,[source_width] - shr ecx,1 - rep movsd - pop edi - pop esi - add [old_dest],edi - mov edi,[old_dest] - - dec [source_height] - jnz ??each_line_loop - - popad - ret - -Asm_Interpolate_Line_Double endp - - - - - - - - - - ;ends - - _TEXT$mycode ends - .data;dataseg - -TopLine dd 640 dup (?) -BottomLine dd 640 dup (?) -LineBuffer dd 640 dup (?) - - _TEXT$mycode segment page public use32 'CODE' ; segment mycode page public use32 'code' ; Need stricter segment alignment - - -Interpolate_Single_Line proc near \ - \ - , source_ptr:dword \ - , dest_ptr:dword \ - , source_width:dword - - pushad - - mov ecx,[source_width] - sub ecx,2 - shr ecx,1 - - mov esi,[source_ptr] - mov edi,[dest_ptr] - -??interpolate_loop: - mov eax,dword ptr[esi] - lea esi,[esi+2] - mov edx,eax - mov ebx,eax - and edx,65535 - ror ebx,8 - mov bl,[edx+PaletteInterpolationTable] - mov bh,ah - and eax,000ffff00h - ror ebx,8 - - ;1st 3 pixels now in ebx - shr eax,8 - mov bh,[eax+PaletteInterpolationTable] - ror ebx,16 - mov [edi],ebx - add edi,4 - - dec ecx - jnz ??interpolate_loop - -; do the last three pixels and a blank - - xor eax,eax - mov ax,word ptr[esi] - mov [edi],al - inc edi - mov al,[eax+PaletteInterpolationTable] - mov [edi],al - inc edi - mov [edi],ah - inc edi - mov byte ptr[edi],0 - - popad - ret - - -Interpolate_Single_Line endp - - -Interpolate_Between_Lines proc near \ - \ - , source1:dword \ - , source2:dword \ - , destination:dword \ - , source_width:dword - - pushad - mov esi,[source1] - mov edi,[destination] - mov ebx,[source2] - xor eax,eax - mov ecx,[source_width] - add ecx,ecx - -??interpolate_each_pixel_loop: - mov al,byte ptr[esi] - mov ah,[ebx] - inc esi - inc ebx - mov dl,[eax+PaletteInterpolationTable] - mov [edi],dl - inc edi - dec ecx - jnz ??interpolate_each_pixel_loop - - popad - ret - -Interpolate_Between_Lines endp - - - - -Lineswp macro - push [next_line] - push [last_line] - pop [next_line] - pop [last_line] -endm - - -Asm_Interpolate_Line_Interpolate PROC near \ - \ - \ - , src_ptr:dword \ - , dest_ptr:dword \ - , source_lines:dword \ - , source_width:dword \ - , dest_width:dword \ - - LOCAL old_dest:dword - LOCAL pixel_count:dword - LOCAL next_line:dword - LOCAL last_line:dword - - pushad - - mov eax,[dest_ptr] - mov [old_dest],eax - - mov [next_line],offset TopLine - mov [last_line],offset BottomLine - mov ecx,[source_width] - shr ecx,1 - mov [pixel_count],ecx - shr [dest_width],1 - - invoke Interpolate_Single_Line,[src_ptr],[next_line],[source_width] - mov esi,[source_width] - Lineswp - add [src_ptr],esi - dec [source_lines] - - -??each_line_pair_loop: - invoke Interpolate_Single_Line,[src_ptr],[next_line],[source_width] - invoke Interpolate_Between_Lines,[last_line],[next_line],offset LineBuffer,[source_width] - - mov esi,[last_line] - mov edi,[old_dest] - mov ecx,[pixel_count] - rep movsd - - mov edi,[old_dest] - mov esi,offset LineBuffer - add edi,[dest_width] - mov ecx,[pixel_count] - mov [old_dest],edi - rep movsd - - mov edi,[old_dest] - mov esi,[source_width] - add edi,[dest_width] - add [src_ptr],esi - mov [old_dest],edi - - Lineswp - dec [source_lines] - jnz ??each_line_pair_loop - - invoke Interpolate_Single_Line,[src_ptr],[next_line],[source_width] - mov esi,[next_line] - mov edi,[old_dest] - mov ecx,[pixel_count] - rep movsd - - popad - ret - - -Asm_Interpolate_Line_Interpolate endp - - ;ends mycode - - - - -public C Asm_Create_Palette_Interpolation_Table -extern C InterpolationPalette:dword - - ;codeseg - - -Asm_Create_Palette_Interpolation_Table proc near - - LOCAL palette_counter:dword - LOCAL first_palette:dword - LOCAL second_palette:dword - LOCAL dest_ptr:dword - LOCAL count:dword - LOCAL closest_colour:dword - LOCAL distance_of_closest:dword - - pushad - - mov [dest_ptr],0 - mov [palette_counter],256 - mov esi,[InterpolationPalette] - -??palette_outer_loop: - mov edi,[InterpolationPalette] - mov ecx,256 - -??palette_inner_loop: - mov bl,byte ptr[esi] - add bl,[edi] - shr bl,1 - - mov bh,byte ptr[esi+1] - add bh,[edi+1] - shr bh,1 - - mov dl,byte ptr[esi+2] - add dl,[edi+2] - shr dl,1 - - mov [closest_colour],0 - mov [distance_of_closest],-1 - - push edi - push ecx - mov edi,[InterpolationPalette] - mov [count],0 - -??cmp_pal_lp: xor eax,eax - xor ecx,ecx - mov al,[edi] - sub al,bl - imul al - mov ecx,eax - mov al,[edi+1] - sub al,bh - imul al - add ecx,eax - mov al,[edi+2] - sub al,dl - imul al - add ecx,eax - - cmp ecx,[distance_of_closest] - ja ??end_cmp_lp - mov [distance_of_closest],ecx - mov eax,[count] - mov [closest_colour],eax - test ecx,ecx - jz ??got_perfect - -??end_cmp_lp: lea edi,[edi+3] - inc [count] - cmp [count],256 - jb ??cmp_pal_lp - - -??got_perfect: mov edi,[dest_ptr] - mov eax,[closest_colour] - mov [edi+PaletteInterpolationTable],al - inc [dest_ptr] - - pop ecx - pop edi - lea edi,[edi+3] - dec ecx - jnz ??palette_inner_loop - - lea esi,[esi+3] - dec [palette_counter] - jnz ??palette_outer_loop - - popad - ret - -Asm_Create_Palette_Interpolation_Table endp - - - _TEXT$mycode ends - -end From 3eb428207d1163bee574fb5536cafcecbfcda154 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:58:06 +0200 Subject: [PATCH 04/14] Use // prose and drop restating comments in voxlib --- code/voxlib.cpp | 126 ++++++++---------------------------------------- 1 file changed, 20 insertions(+), 106 deletions(-) diff --git a/code/voxlib.cpp b/code/voxlib.cpp index d143ba3b..f6186c05 100644 --- a/code/voxlib.cpp +++ b/code/voxlib.cpp @@ -86,7 +86,7 @@ const Vector3 *VoxelNormalTables[] = }; -/// warning C4305: 'argument' : truncation from 'const double' to 'float' +// warning C4305: 'argument' : truncation from 'const double' to 'float' #pragma warning(disable : 4305) float VoxelNormals1[][3] = { @@ -837,17 +837,14 @@ void VoxelLibrary::Render_Object(VoxelRenderStruct & voxel, Vector3 & center) /// The projection, stride and voxel data setup for this object. static void __cdecl _voxel_draw_shadow(VoxelFuncArgumentStruct * state) { - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->EndOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -860,13 +857,11 @@ static void __cdecl _voxel_draw_shadow(VoxelFuncArgumentStruct * state) VoxelDrawBuffer[buffer_index + 1] = color_index; } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -929,33 +924,24 @@ void VoxelLibrary::Render_Shadow(VoxelShadowRenderStruct & voxel, Vector3 & cent /// void VoxelLibrary::Compute_Bounding_Box(void) { - /// Compute the coordinates of the eight corners of the bounding box. for (unsigned i = 0; i < LayerInfoCount; i++) { LayerInfoStruct &layerinfo = LayerInfos[i]; - // +x +y -z layerinfo.BoxCorner[VOXEL_BOUNDS_BFR] = Vector3(+layerinfo.XSize / 2.0f, +layerinfo.YSize / 2.0f, -layerinfo.ZSize / 2.0f); - // +x -y -z layerinfo.BoxCorner[VOXEL_BOUNDS_BBR] = Vector3(+layerinfo.XSize / 2.0f, -layerinfo.YSize / 2.0f, -layerinfo.ZSize / 2.0f); - // -x -y -z layerinfo.BoxCorner[VOXEL_BOUNDS_BBL] = Vector3(-layerinfo.XSize / 2.0f, -layerinfo.YSize / 2.0f, -layerinfo.ZSize / 2.0f); - // -x +y -z layerinfo.BoxCorner[VOXEL_BOUNDS_BFL] = Vector3(-layerinfo.XSize / 2.0f, +layerinfo.YSize / 2.0f, -layerinfo.ZSize / 2.0f); - // +x +y +z layerinfo.BoxCorner[VOXEL_BOUNDS_TFR] = Vector3(+layerinfo.XSize / 2.0f, +layerinfo.YSize / 2.0f, +layerinfo.ZSize / 2.0f); - // +x -y +z layerinfo.BoxCorner[VOXEL_BOUNDS_TBR] = Vector3(+layerinfo.XSize / 2.0f, -layerinfo.YSize / 2.0f, +layerinfo.ZSize / 2.0f); - // -x -y +z layerinfo.BoxCorner[VOXEL_BOUNDS_TBL] = Vector3(-layerinfo.XSize / 2.0f, -layerinfo.YSize / 2.0f, +layerinfo.ZSize / 2.0f); - // -x +y +z layerinfo.BoxCorner[VOXEL_BOUNDS_TFL] = Vector3(-layerinfo.XSize / 2.0f, +layerinfo.YSize / 2.0f, +layerinfo.ZSize / 2.0f); } } -/// The three variants that follow build the same table and differ only in whether each -/// store goes through the local reference or names VoxelPixelDeltaTable outright. Which -/// variant a drawer calls is deliberate; do not merge them. +// The three variants that follow build the same table and differ only in whether each +// store goes through the local reference or names VoxelPixelDeltaTable outright. Which +// variant a drawer calls is deliberate; do not merge them. /// /// Fills in the voxel projection delta table. @@ -1041,17 +1027,14 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->StartOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1061,7 +1044,7 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1094,8 +1077,7 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) */ ptr++; - /// Compute buffer index and write color. A voxel covers two - /// buffer bytes, so the colour goes down twice. + // A voxel covers two buffer bytes, so the colour goes down twice. unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); VoxelDrawBuffer[buffer_index] = color_index; VoxelDrawBuffer[buffer_index + 1] = color_index; @@ -1111,13 +1093,11 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1140,17 +1120,14 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table1(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->EndOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1160,7 +1137,7 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1182,8 +1159,7 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr--; - /// Compute buffer index and write color. A voxel covers two - /// buffer bytes, so the colour goes down twice. + // A voxel covers two buffer bytes, so the colour goes down twice. unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); VoxelDrawBuffer[buffer_index] = color_index; VoxelDrawBuffer[buffer_index + 1] = color_index; @@ -1210,13 +1186,11 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1239,19 +1213,16 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table3(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -1262,7 +1233,7 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1297,7 +1268,6 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer(VoxelFuncArgumentStruct * state) */ ptr++; - /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { VoxelDrawZBuffer[buffer_index] = (pixel_z >> 8); @@ -1318,14 +1288,12 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer(VoxelFuncArgumentStruct * state) } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -1349,19 +1317,16 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -1372,7 +1337,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1400,7 +1365,6 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer(VoxelFuncArgumentStruct * state) value = *ptr; ptr--; - /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { VoxelDrawZBuffer[buffer_index] = (pixel_z >> 8); @@ -1433,14 +1397,12 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer(VoxelFuncArgumentStruct * state) } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -1464,17 +1426,14 @@ void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state */ Fill_Delta_Table1(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->StartOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1484,7 +1443,7 @@ void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1519,7 +1478,6 @@ void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state unsigned char table_index = VoxelNormalTranslateTable[normal_index]; ptr++; - /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); color_index = VoxelPaletteTranslateTable[table_index][color_index]; @@ -1537,13 +1495,11 @@ void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1566,17 +1522,14 @@ void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state */ Fill_Delta_Table2(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->EndOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1586,7 +1539,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1610,7 +1563,6 @@ void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state unsigned char color_index = *ptr; ptr--; - /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); color_index = VoxelPaletteTranslateTable[table_index][color_index]; @@ -1639,13 +1591,11 @@ void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1668,19 +1618,16 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct */ Fill_Delta_Table2(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -1691,7 +1638,7 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1714,7 +1661,6 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct remaining -= run_length; while (run_length) { - /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { @@ -1761,14 +1707,12 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -1792,19 +1736,16 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct */ Fill_Delta_Table1(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -1815,7 +1756,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1826,7 +1767,6 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct remaining -= run_length; while (run_length) { - /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { @@ -1886,14 +1826,12 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -1916,17 +1854,14 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table1(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->StartOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1936,7 +1871,7 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1964,8 +1899,7 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr++; - /// Compute buffer index and write color. Unlike the shaded - /// drawers, this one covers a single buffer byte per voxel. + // Unlike the shaded drawers, this one covers a single buffer byte per voxel. VoxelDrawBuffer[(pixel_x >> 8) | (pixel_y & 0xFF00)] = color_index; pixel_x += state->TransformMatrix[3].I; @@ -1979,13 +1913,11 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -2007,17 +1939,14 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->EndOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -2027,7 +1956,7 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -2044,8 +1973,7 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr--; - /// Compute buffer index and write color. Unlike the shaded - /// drawers, this one covers a single buffer byte per voxel. + // Unlike the shaded drawers, this one covers a single buffer byte per voxel. VoxelDrawBuffer[(pixel_x >> 8) | (pixel_y & 0xFF00)] = color_index; pixel_x += state->TransformMatrix[3].I; @@ -2070,13 +1998,11 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -2099,19 +2025,16 @@ void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -2122,7 +2045,7 @@ void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -2152,7 +2075,6 @@ void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state) value = *ptr; ptr++; - /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { VoxelDrawZBuffer[buffer_index] = (pixel_z >> 8); @@ -2173,14 +2095,12 @@ void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state) } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -2204,19 +2124,16 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); - /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; - /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; - /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -2227,7 +2144,7 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - /// Parse voxel run-length encoded data along Z axis + // Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -2250,7 +2167,6 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state) value = *ptr; ptr--; - /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { VoxelDrawZBuffer[buffer_index] = (pixel_z >> 8); @@ -2283,14 +2199,12 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state) } } - /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } - /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; From 5566540c99bdaa939fdba03c72837922d9e2ac6b Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:59:04 +0200 Subject: [PATCH 05/14] Remove the non-MMX spot light brightening path --- code/colorops.cpp | 109 -------------------------------- code/ovrlight.cpp | 33 ++-------- tests/colorops/coloropstest.cpp | 22 +++---- 3 files changed, 14 insertions(+), 150 deletions(-) diff --git a/code/colorops.cpp b/code/colorops.cpp index c1648281..a5c2332d 100644 --- a/code/colorops.cpp +++ b/code/colorops.cpp @@ -21,24 +21,6 @@ #include "always.h" -/* - * Two families of routine, each replacing four assembly routines of the same names, one per - * hicolor layout. - * - * Adjust_Color_* builds a palette translation table: every colour is scaled and packed into a - * pixel. A colour whose mask entry is set is scaled by the separate red, green and blue tints; - * one whose entry is clear is scaled by the single intensity instead. - * - * Brighten_Color_* and MMX_Brighten_Color_* lighten a hicolor image through a per-pixel - * multiplier. The two reach the same shape by different routes -- the first unpacks each pixel - * with shifts, the second reads the channels out of a caller-supplied 65536 entry table -- and - * they are kept apart here rather than folded together, because only the caller knows whether - * the table it built agrees with the shifts. - * - * The assembly had three hand-written paths through Adjust_Color, chosen at run time by the - * MMX and CMOV flags. All three computed the same thing, so one routine replaces them. - */ - namespace { /* @@ -108,32 +90,6 @@ void Adjust_Color(unsigned char const * palette, unsigned short * translator, in } -/* - * How one layout is taken apart and put back together by the brightening routines. The names - * follow the order the assembly worked in rather than red, green, blue. - */ -struct BrightenFormat { - unsigned int ShiftA; - unsigned int ShiftB; - unsigned int MaskA; - unsigned int MaskB; - unsigned int ScaleShiftA; - unsigned int ScaleShiftB; - unsigned int DownA; - unsigned int DownB; - unsigned int UpA; - unsigned int UpB; - unsigned int ShiftC; - unsigned int ScaleShiftC; - unsigned int DownC; -}; - -BrightenFormat const _Brighten565 = {8, 3, 0xF8, 0xFC, 8, 8, 3, 2, 11, 5, 3, 8, 3}; -BrightenFormat const _Brighten655 = {8, 2, 0xFC, 0xF8, 8, 8, 2, 3, 10, 5, 3, 8, 3}; -BrightenFormat const _Brighten556 = {8, 3, 0xF8, 0xF8, 8, 8, 3, 3, 11, 6, 2, 8, 2}; -BrightenFormat const _Brighten555 = {7, 2, 0xF8, 0xF8, 8, 8, 3, 3, 10, 5, 3, 8, 3}; - - /// /// Adds two channel values, holding the result at 255 rather than letting it wrap. /// @@ -147,47 +103,6 @@ inline unsigned int Add_Saturated(unsigned int left, unsigned int right) } -void Brighten_Color(unsigned char const * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, - int colorbuffwidth, int width, int height, BrightenFormat const & format) -{ - unsigned char const * mulrow = mulbuffer; - unsigned char * colorrow = (unsigned char *)colorbuffer; - - for (int y = 0; y < height; y++) { - unsigned char const * mul = mulrow; - unsigned short * color = (unsigned short *)colorrow; - - for (int x = 0; x < width; x++) { - unsigned int const multiplier = *mul; - - if (multiplier != 0) { - unsigned int const pixel = *color; - - unsigned int const a = (pixel >> format.ShiftA) & format.MaskA; - unsigned int const b = (pixel >> format.ShiftB) & format.MaskB; - unsigned int const c = (pixel << format.ShiftC) & 0xFF; - - unsigned int outa = Add_Saturated((a * multiplier) >> format.ScaleShiftA, a); - unsigned int outb = Add_Saturated((b * multiplier) >> format.ScaleShiftB, b); - unsigned int outc = Add_Saturated((c * multiplier) >> format.ScaleShiftC, c); - - outa = (outa >> format.DownA) << format.UpA; - outb = (outb >> format.DownB) << format.UpB; - outc = outc >> format.DownC; - - *color = (unsigned short)(outa | outb | outc); - } - - mul++; - color++; - } - - mulrow += mulbuffwidth; - colorrow += colorbuffwidth; - } -} - - /* * How the table-driven brightening puts a pixel back together. The channels arrive already * separated, so only the reassembly differs between layouts. @@ -299,30 +214,6 @@ void __cdecl Adjust_Color_655(void * palette, void * translator, int red, int gr } -void __cdecl Brighten_Color_565(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height) -{ - Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, _Brighten565); -} - - -void __cdecl Brighten_Color_555(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height) -{ - Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, _Brighten555); -} - - -void __cdecl Brighten_Color_556(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height) -{ - Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, _Brighten556); -} - - -void __cdecl Brighten_Color_655(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height) -{ - Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, _Brighten655); -} - - void __cdecl MMX_Brighten_Color_565(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) { MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten565); diff --git a/code/ovrlight.cpp b/code/ovrlight.cpp index 13e2b8e8..dbb4a7ae 100644 --- a/code/ovrlight.cpp +++ b/code/ovrlight.cpp @@ -36,18 +36,13 @@ BSurface *SpotLightSurfaces[SpotLightClass::SPOTLIGHT_SURFACE_COUNT + SpotLightC extern "C" { /* - * Externs to assembly routines from winasm.asm + * Externs to the colour routines in colorops.cpp */ void __cdecl Adjust_Color_565(void *pal1, void *pal2, int red, int green, int blue, int intensity, char *arg7); void __cdecl Adjust_Color_555(void *pal1, void *pal2, int red, int green, int blue, int intensity, char *arg7); void __cdecl Adjust_Color_556(void *pal1, void *pal2, int red, int green, int blue, int intensity, char *arg7); void __cdecl Adjust_Color_655(void *pal1, void *pal2, int red, int green, int blue, int intensity, char *arg7); -void __cdecl Brighten_Color_565(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int width, int height); -void __cdecl Brighten_Color_555(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int width, int height); -void __cdecl Brighten_Color_556(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int width, int height); -void __cdecl Brighten_Color_655(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int width, int height); - void __cdecl MMX_Brighten_Color_565(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *mmx_buffer); void __cdecl MMX_Brighten_Color_555(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *mmx_buffer); void __cdecl MMX_Brighten_Color_556(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *mmx_buffer); @@ -240,39 +235,23 @@ void SpotLightClass::Draw_It(void) unsigned char *sptr_row = sptr; unsigned short *dptr_row = dptr; - if (SpotLightDontUseMMX != 1) { + if (SpotLightDontUseMMX != 1 && SpotLightMMXBuffer != NULL) { switch (SpotLightColorMode) { case COLORMODE_555: - if (SpotLightMMXBuffer) { - MMX_Brighten_Color_555(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); - } else { - Brighten_Color_555(sptr, dptr, 256, stride, srect.Width, srect.Height); - } + MMX_Brighten_Color_555(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); break; case COLORMODE_556: - if (SpotLightMMXBuffer) { - MMX_Brighten_Color_556(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); - } else { - Brighten_Color_556(sptr, dptr, 256, stride, srect.Width, srect.Height); - } + MMX_Brighten_Color_556(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); break; case COLORMODE_565: - if (SpotLightMMXBuffer) { - MMX_Brighten_Color_565(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); - } else { - Brighten_Color_565(sptr, dptr, 256, stride, srect.Width, srect.Height); - } + MMX_Brighten_Color_565(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); break; case COLORMODE_655: - if (SpotLightMMXBuffer) { - MMX_Brighten_Color_655(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); - } else { - Brighten_Color_655(sptr, dptr, 256, stride, srect.Width, srect.Height); - } + MMX_Brighten_Color_655(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); break; default: diff --git a/tests/colorops/coloropstest.cpp b/tests/colorops/coloropstest.cpp index 00d8b941..834de892 100644 --- a/tests/colorops/coloropstest.cpp +++ b/tests/colorops/coloropstest.cpp @@ -24,11 +24,6 @@ void __cdecl Adjust_Color_555(void *pal, void *xlat, int r, int g, int b, int i, void __cdecl Adjust_Color_556(void *pal, void *xlat, int r, int g, int b, int i, void *mask); void __cdecl Adjust_Color_655(void *pal, void *xlat, int r, int g, int b, int i, void *mask); -void __cdecl Brighten_Color_565(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h); -void __cdecl Brighten_Color_555(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h); -void __cdecl Brighten_Color_556(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h); -void __cdecl Brighten_Color_655(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h); - void __cdecl MMX_Brighten_Color_565(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); void __cdecl MMX_Brighten_Color_555(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); void __cdecl MMX_Brighten_Color_556(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); @@ -71,11 +66,9 @@ unsigned long long Hash(void const * data, int size) typedef void (__cdecl * AdjustFunc)(void *, void *, int, int, int, int, void *); -typedef void (__cdecl * BrightenFunc)(unsigned char *, unsigned short *, int, int, int, int); typedef void (__cdecl * MmxBrightenFunc)(unsigned char *, unsigned short *, int, int, int, int, int *); AdjustFunc const Adjusts[4] = {Adjust_Color_565, Adjust_Color_555, Adjust_Color_556, Adjust_Color_655}; -BrightenFunc const Brightens[4] = {Brighten_Color_565, Brighten_Color_555, Brighten_Color_556, Brighten_Color_655}; MmxBrightenFunc const MmxBrightens[4] = {MMX_Brighten_Color_565, MMX_Brighten_Color_555, MMX_Brighten_Color_556, MMX_Brighten_Color_655}; char const * const ModeNames[4] = {"565", "555", "556", "655"}; @@ -137,6 +130,11 @@ int main(void) for (int i = 0; i < BrightenGoldenCaseCount; i++) { BrightenGoldenCase const & test = BrightenGoldenCases[i]; + // The non-MMX vectors record a path colorops.cpp no longer has. + if (test.Mmx == 0) { + continue; + } + Seed = test.Seed; for (int j = 0; j < 256 * 256; j++) { @@ -149,17 +147,13 @@ int main(void) MmxBuffer[j] = (int)(Next_Random() & 0x00FFFFFF); } - if (test.Mmx != 0) { - MmxBrightens[test.Mode](MulBuffer, ColorBuffer, 256, 512 * 2, test.Width, test.Height, MmxBuffer); - } else { - Brightens[test.Mode](MulBuffer, ColorBuffer, 256, 512 * 2, test.Width, test.Height); - } + MmxBrightens[test.Mode](MulBuffer, ColorBuffer, 256, 512 * 2, test.Width, test.Height, MmxBuffer); unsigned long long const hash = Hash(ColorBuffer, 512 * 512 * 2); if (hash != test.Hash) { - std::printf("FAILED %sBrighten_Color_%s %dx%d: expected %llu, got %llu\n", - test.Mmx ? "MMX_" : "", ModeNames[test.Mode], test.Width, test.Height, test.Hash, hash); + std::printf("FAILED MMX_Brighten_Color_%s %dx%d: expected %llu, got %llu\n", + ModeNames[test.Mode], test.Width, test.Height, test.Hash, hash); Failures++; } From 93950fc3bdb5742c32a557101647438b84835ddc Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:59:44 +0200 Subject: [PATCH 06/14] Drop the MMX prefix and use sized integer types in colorops --- code/colorops.cpp | 161 ++++++++++++++++---------------- code/ovrlight.cpp | 16 ++-- tests/colorops/coloropstest.cpp | 20 ++-- 3 files changed, 100 insertions(+), 97 deletions(-) diff --git a/code/colorops.cpp b/code/colorops.cpp index a5c2332d..d189646e 100644 --- a/code/colorops.cpp +++ b/code/colorops.cpp @@ -21,6 +21,8 @@ #include "always.h" +#include + namespace { /* @@ -28,12 +30,12 @@ namespace { * carry, and the shift moves them into place; red and green shift up, blue shifts down. */ struct PackFormat { - unsigned int RedMask; - unsigned int RedShift; - unsigned int GreenMask; - unsigned int GreenShift; - unsigned int BlueMask; - unsigned int BlueShift; + std::uint32_t RedMask; + std::uint32_t RedShift; + std::uint32_t GreenMask; + std::uint32_t GreenShift; + std::uint32_t BlueMask; + std::uint32_t BlueShift; }; PackFormat const _Format565 = {0xF8, 8, 0xFC, 3, 0xF8, 3}; @@ -48,42 +50,42 @@ PackFormat const _Format655 = {0xFC, 8, 0xF8, 2, 0xF8, 3}; /// /// The channel value, 0 to 255. /// The 16.16 fixed point factor to scale it by. -/// unsigned int; The scaled channel, at most 255. -inline unsigned int Scale_Channel(unsigned int channel, unsigned int scale) +/// std::uint32_t; The scaled channel, at most 255. +inline std::uint32_t Scale_Channel(std::uint32_t channel, std::uint32_t scale) { - unsigned int const scaled = (unsigned int)(channel * scale) >> 16; + std::uint32_t const scaled = (std::uint32_t)(channel * scale) >> 16; return((scaled > 255) ? 255 : scaled); } -void Adjust_Color(unsigned char const * palette, unsigned short * translator, int red, int green, int blue, - int intensity, unsigned char const * mask, PackFormat const & format) +void Adjust_Color(std::uint8_t const * palette, std::uint16_t * translator, std::int32_t red, std::int32_t green, + std::int32_t blue, std::int32_t intensity, std::uint8_t const * mask, PackFormat const & format) { /* * Index zero is the transparent one and is never scaled. */ translator[0] = 0; - for (int i = 1; i < 256; i++) { - unsigned int const r = palette[i * 3 + 0]; - unsigned int const g = palette[i * 3 + 1]; - unsigned int const b = palette[i * 3 + 2]; + for (std::int32_t i = 1; i < 256; i++) { + std::uint32_t const r = palette[i * 3 + 0]; + std::uint32_t const g = palette[i * 3 + 1]; + std::uint32_t const b = palette[i * 3 + 2]; - unsigned int redscale = (unsigned int)intensity; - unsigned int greenscale = (unsigned int)intensity; - unsigned int bluescale = (unsigned int)intensity; + std::uint32_t redscale = (std::uint32_t)intensity; + std::uint32_t greenscale = (std::uint32_t)intensity; + std::uint32_t bluescale = (std::uint32_t)intensity; if (mask[i] != 0) { - redscale = (unsigned int)red; - greenscale = (unsigned int)green; - bluescale = (unsigned int)blue; + redscale = (std::uint32_t)red; + greenscale = (std::uint32_t)green; + bluescale = (std::uint32_t)blue; } - unsigned int const outr = Scale_Channel(r, redscale); - unsigned int const outg = Scale_Channel(g, greenscale); - unsigned int const outb = Scale_Channel(b, bluescale); + std::uint32_t const outr = Scale_Channel(r, redscale); + std::uint32_t const outg = Scale_Channel(g, greenscale); + std::uint32_t const outb = Scale_Channel(b, bluescale); - translator[i] = (unsigned short)(((outr & format.RedMask) << format.RedShift) + translator[i] = (std::uint16_t)(((outr & format.RedMask) << format.RedShift) | ((outg & format.GreenMask) << format.GreenShift) | ((outb & format.BlueMask) >> format.BlueShift)); } @@ -95,10 +97,10 @@ void Adjust_Color(unsigned char const * palette, unsigned short * translator, in /// /// One value. /// The other. -/// unsigned int; The sum, at most 255. -inline unsigned int Add_Saturated(unsigned int left, unsigned int right) +/// std::uint32_t; The sum, at most 255. +inline std::uint32_t Add_Saturated(std::uint32_t left, std::uint32_t right) { - unsigned int const sum = (left & 0xFF) + (right & 0xFF); + std::uint32_t const sum = (left & 0xFF) + (right & 0xFF); return((sum > 255) ? 255 : sum); } @@ -107,12 +109,12 @@ inline unsigned int Add_Saturated(unsigned int left, unsigned int right) * How the table-driven brightening puts a pixel back together. The channels arrive already * separated, so only the reassembly differs between layouts. */ -struct MmxBrightenFormat { - unsigned int Down; - unsigned int BlueDown; - unsigned int GreenUp; - unsigned int RedUp; - unsigned int Mask; +struct BrightenFormat { + std::uint32_t Down; + std::uint32_t BlueDown; + std::uint32_t GreenUp; + std::uint32_t RedUp; + std::uint32_t Mask; }; /* @@ -121,59 +123,60 @@ struct MmxBrightenFormat { * well. It is preserved because the recorded output depends on it, not because it reads like a * mask anyone intended. */ -unsigned int const MMX_ALTERNATE_MARKER = 0x423A0A60; +std::uint32_t const ALTERNATE_MARKER = 0x423A0A60; -MmxBrightenFormat const _MmxBrighten565 = {2, 1, 5, 10, 0xF8}; -MmxBrightenFormat const _MmxBrighten555 = {3, 0, 5, 10, 0x7C}; -MmxBrightenFormat const _MmxBrighten556 = {2, 0, 6, 10, 0xF8}; -MmxBrightenFormat const _MmxBrighten655 = {2, 1, 4, 10, MMX_ALTERNATE_MARKER}; +BrightenFormat const _Brighten565 = {2, 1, 5, 10, 0xF8}; +BrightenFormat const _Brighten555 = {3, 0, 5, 10, 0x7C}; +BrightenFormat const _Brighten556 = {2, 0, 6, 10, 0xF8}; +BrightenFormat const _Brighten655 = {2, 1, 4, 10, ALTERNATE_MARKER}; -void MMX_Brighten_Color(unsigned char const * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, - int colorbuffwidth, int width, int height, int const * mmxbuffer, MmxBrightenFormat const & format) +void Brighten_Color(std::uint8_t const * mulbuffer, std::uint16_t * colorbuffer, std::int32_t mulbuffwidth, + std::int32_t colorbuffwidth, std::int32_t width, std::int32_t height, std::int32_t const * colortable, + BrightenFormat const & format) { - unsigned char const * mulrow = mulbuffer; - unsigned char * colorrow = (unsigned char *)colorbuffer; + std::uint8_t const * mulrow = mulbuffer; + std::uint8_t * colorrow = (std::uint8_t *)colorbuffer; - for (int y = 0; y < height; y++) { - unsigned char const * mul = mulrow; - unsigned short * color = (unsigned short *)colorrow; + for (std::int32_t y = 0; y < height; y++) { + std::uint8_t const * mul = mulrow; + std::uint16_t * color = (std::uint16_t *)colorrow; - for (int x = 0; x < width; x++) { - unsigned int const multiplier = *mul; + for (std::int32_t x = 0; x < width; x++) { + std::uint32_t const multiplier = *mul; if (multiplier != 0) { - unsigned int const pixel = *color; - unsigned int const entry = (unsigned int)mmxbuffer[pixel]; + std::uint32_t const pixel = *color; + std::uint32_t const entry = (std::uint32_t)colortable[pixel]; /* * The table holds the three channels one per byte, which the assembly * widened to a word each before scaling them together. */ - unsigned int const blue = entry & 0xFF; - unsigned int const green = (entry >> 8) & 0xFF; - unsigned int const red = (entry >> 16) & 0xFF; + std::uint32_t const blue = entry & 0xFF; + std::uint32_t const green = (entry >> 8) & 0xFF; + std::uint32_t const red = (entry >> 16) & 0xFF; - unsigned int const outblue = Add_Saturated((blue * multiplier) >> 8, blue) >> format.Down; - unsigned int const outgreen = Add_Saturated((green * multiplier) >> 8, green) >> format.Down; - unsigned int const outred = Add_Saturated((red * multiplier) >> 8, red) >> format.Down; + std::uint32_t const outblue = Add_Saturated((blue * multiplier) >> 8, blue) >> format.Down; + std::uint32_t const outgreen = Add_Saturated((green * multiplier) >> 8, green) >> format.Down; + std::uint32_t const outred = Add_Saturated((red * multiplier) >> 8, red) >> format.Down; - unsigned int result = outblue >> format.BlueDown; - unsigned int const greenpart = outgreen << format.GreenUp; - unsigned int const redpart = outred << format.RedUp; + std::uint32_t result = outblue >> format.BlueDown; + std::uint32_t const greenpart = outgreen << format.GreenUp; + std::uint32_t const redpart = outred << format.RedUp; - if (format.Mask == MMX_ALTERNATE_MARKER) { - result |= (greenpart & MMX_ALTERNATE_MARKER); + if (format.Mask == ALTERNATE_MARKER) { + result |= (greenpart & ALTERNATE_MARKER); } else { result |= greenpart; result |= (redpart & (format.Mask * 256)); } - if (format.Mask == MMX_ALTERNATE_MARKER) { + if (format.Mask == ALTERNATE_MARKER) { result |= redpart; } - *color = (unsigned short)result; + *color = (std::uint16_t)result; } mul++; @@ -190,51 +193,51 @@ void MMX_Brighten_Color(unsigned char const * mulbuffer, unsigned short * colorb extern "C" { -void __cdecl Adjust_Color_565(void * palette, void * translator, int red, int green, int blue, int intensity, void * mask) +void __cdecl Adjust_Color_565(void * palette, void * translator, std::int32_t red, std::int32_t green, std::int32_t blue, std::int32_t intensity, void * mask) { - Adjust_Color((unsigned char const *)palette, (unsigned short *)translator, red, green, blue, intensity, (unsigned char const *)mask, _Format565); + Adjust_Color((std::uint8_t const *)palette, (std::uint16_t *)translator, red, green, blue, intensity, (std::uint8_t const *)mask, _Format565); } -void __cdecl Adjust_Color_555(void * palette, void * translator, int red, int green, int blue, int intensity, void * mask) +void __cdecl Adjust_Color_555(void * palette, void * translator, std::int32_t red, std::int32_t green, std::int32_t blue, std::int32_t intensity, void * mask) { - Adjust_Color((unsigned char const *)palette, (unsigned short *)translator, red, green, blue, intensity, (unsigned char const *)mask, _Format555); + Adjust_Color((std::uint8_t const *)palette, (std::uint16_t *)translator, red, green, blue, intensity, (std::uint8_t const *)mask, _Format555); } -void __cdecl Adjust_Color_556(void * palette, void * translator, int red, int green, int blue, int intensity, void * mask) +void __cdecl Adjust_Color_556(void * palette, void * translator, std::int32_t red, std::int32_t green, std::int32_t blue, std::int32_t intensity, void * mask) { - Adjust_Color((unsigned char const *)palette, (unsigned short *)translator, red, green, blue, intensity, (unsigned char const *)mask, _Format556); + Adjust_Color((std::uint8_t const *)palette, (std::uint16_t *)translator, red, green, blue, intensity, (std::uint8_t const *)mask, _Format556); } -void __cdecl Adjust_Color_655(void * palette, void * translator, int red, int green, int blue, int intensity, void * mask) +void __cdecl Adjust_Color_655(void * palette, void * translator, std::int32_t red, std::int32_t green, std::int32_t blue, std::int32_t intensity, void * mask) { - Adjust_Color((unsigned char const *)palette, (unsigned short *)translator, red, green, blue, intensity, (unsigned char const *)mask, _Format655); + Adjust_Color((std::uint8_t const *)palette, (std::uint16_t *)translator, red, green, blue, intensity, (std::uint8_t const *)mask, _Format655); } -void __cdecl MMX_Brighten_Color_565(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) +void __cdecl Brighten_Color_565(std::uint8_t * mulbuffer, std::uint16_t * colorbuffer, std::int32_t mulbuffwidth, std::int32_t colorbuffwidth, std::int32_t width, std::int32_t height, std::int32_t * colortable) { - MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten565); + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, colortable, _Brighten565); } -void __cdecl MMX_Brighten_Color_555(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) +void __cdecl Brighten_Color_555(std::uint8_t * mulbuffer, std::uint16_t * colorbuffer, std::int32_t mulbuffwidth, std::int32_t colorbuffwidth, std::int32_t width, std::int32_t height, std::int32_t * colortable) { - MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten555); + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, colortable, _Brighten555); } -void __cdecl MMX_Brighten_Color_556(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) +void __cdecl Brighten_Color_556(std::uint8_t * mulbuffer, std::uint16_t * colorbuffer, std::int32_t mulbuffwidth, std::int32_t colorbuffwidth, std::int32_t width, std::int32_t height, std::int32_t * colortable) { - MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten556); + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, colortable, _Brighten556); } -void __cdecl MMX_Brighten_Color_655(unsigned char * mulbuffer, unsigned short * colorbuffer, int mulbuffwidth, int colorbuffwidth, int width, int height, int * mmxbuffer) +void __cdecl Brighten_Color_655(std::uint8_t * mulbuffer, std::uint16_t * colorbuffer, std::int32_t mulbuffwidth, std::int32_t colorbuffwidth, std::int32_t width, std::int32_t height, std::int32_t * colortable) { - MMX_Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, mmxbuffer, _MmxBrighten655); + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, colortable, _Brighten655); } } // extern "C" diff --git a/code/ovrlight.cpp b/code/ovrlight.cpp index dbb4a7ae..c7fa5f14 100644 --- a/code/ovrlight.cpp +++ b/code/ovrlight.cpp @@ -43,10 +43,10 @@ void __cdecl Adjust_Color_555(void *pal1, void *pal2, int red, int green, int bl void __cdecl Adjust_Color_556(void *pal1, void *pal2, int red, int green, int blue, int intensity, char *arg7); void __cdecl Adjust_Color_655(void *pal1, void *pal2, int red, int green, int blue, int intensity, char *arg7); -void __cdecl MMX_Brighten_Color_565(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *mmx_buffer); -void __cdecl MMX_Brighten_Color_555(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *mmx_buffer); -void __cdecl MMX_Brighten_Color_556(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *mmx_buffer); -void __cdecl MMX_Brighten_Color_655(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *mmx_buffer); +void __cdecl Brighten_Color_565(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *color_table); +void __cdecl Brighten_Color_555(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *color_table); +void __cdecl Brighten_Color_556(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *color_table); +void __cdecl Brighten_Color_655(unsigned char *mul_buffer, unsigned short *color_buffer, int mulbuff_width, int color_buff_width, int dst_width, int dst_height, int *color_table); } @@ -239,19 +239,19 @@ void SpotLightClass::Draw_It(void) switch (SpotLightColorMode) { case COLORMODE_555: - MMX_Brighten_Color_555(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); + Brighten_Color_555(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); break; case COLORMODE_556: - MMX_Brighten_Color_556(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); + Brighten_Color_556(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); break; case COLORMODE_565: - MMX_Brighten_Color_565(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); + Brighten_Color_565(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); break; case COLORMODE_655: - MMX_Brighten_Color_655(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); + Brighten_Color_655(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); break; default: diff --git a/tests/colorops/coloropstest.cpp b/tests/colorops/coloropstest.cpp index 834de892..c4370411 100644 --- a/tests/colorops/coloropstest.cpp +++ b/tests/colorops/coloropstest.cpp @@ -24,10 +24,10 @@ void __cdecl Adjust_Color_555(void *pal, void *xlat, int r, int g, int b, int i, void __cdecl Adjust_Color_556(void *pal, void *xlat, int r, int g, int b, int i, void *mask); void __cdecl Adjust_Color_655(void *pal, void *xlat, int r, int g, int b, int i, void *mask); -void __cdecl MMX_Brighten_Color_565(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); -void __cdecl MMX_Brighten_Color_555(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); -void __cdecl MMX_Brighten_Color_556(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); -void __cdecl MMX_Brighten_Color_655(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *mmx); +void __cdecl Brighten_Color_565(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *table); +void __cdecl Brighten_Color_555(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *table); +void __cdecl Brighten_Color_556(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *table); +void __cdecl Brighten_Color_655(unsigned char *mul, unsigned short *col, int mw, int cw, int w, int h, int *table); } namespace { @@ -38,7 +38,7 @@ unsigned short Translator[256]; unsigned char MulBuffer[256 * 256]; unsigned short ColorBuffer[512 * 512]; -int MmxBuffer[65536]; +int ColorTable[65536]; unsigned int Seed = 0; @@ -66,10 +66,10 @@ unsigned long long Hash(void const * data, int size) typedef void (__cdecl * AdjustFunc)(void *, void *, int, int, int, int, void *); -typedef void (__cdecl * MmxBrightenFunc)(unsigned char *, unsigned short *, int, int, int, int, int *); +typedef void (__cdecl * BrightenFunc)(unsigned char *, unsigned short *, int, int, int, int, int *); AdjustFunc const Adjusts[4] = {Adjust_Color_565, Adjust_Color_555, Adjust_Color_556, Adjust_Color_655}; -MmxBrightenFunc const MmxBrightens[4] = {MMX_Brighten_Color_565, MMX_Brighten_Color_555, MMX_Brighten_Color_556, MMX_Brighten_Color_655}; +BrightenFunc const Brightens[4] = {Brighten_Color_565, Brighten_Color_555, Brighten_Color_556, Brighten_Color_655}; char const * const ModeNames[4] = {"565", "555", "556", "655"}; @@ -144,15 +144,15 @@ int main(void) ColorBuffer[j] = (unsigned short)(Next_Random() & 0xFFFF); } for (int j = 0; j < 65536; j++) { - MmxBuffer[j] = (int)(Next_Random() & 0x00FFFFFF); + ColorTable[j] = (int)(Next_Random() & 0x00FFFFFF); } - MmxBrightens[test.Mode](MulBuffer, ColorBuffer, 256, 512 * 2, test.Width, test.Height, MmxBuffer); + Brightens[test.Mode](MulBuffer, ColorBuffer, 256, 512 * 2, test.Width, test.Height, ColorTable); unsigned long long const hash = Hash(ColorBuffer, 512 * 512 * 2); if (hash != test.Hash) { - std::printf("FAILED MMX_Brighten_Color_%s %dx%d: expected %llu, got %llu\n", + std::printf("FAILED Brighten_Color_%s %dx%d: expected %llu, got %llu\n", ModeNames[test.Mode], test.Width, test.Height, test.Hash, hash); Failures++; } From 5421a6dd72678097d517debf971d6e60615d4c75 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Wed, 2 Sep 2026 19:04:28 +0200 Subject: [PATCH 07/14] Comment cleanup --- code/colorops.cpp | 8 --- code/voxlib.cpp | 126 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 106 insertions(+), 28 deletions(-) diff --git a/code/colorops.cpp b/code/colorops.cpp index d189646e..144c3ed1 100644 --- a/code/colorops.cpp +++ b/code/colorops.cpp @@ -11,14 +11,6 @@ * disclaimers apply; see LICENSE.md. ******************************************************************************/ -/**************************************************************************** -* -* File : winasm.asm -* Description : Palette tinting and spot light brightening for each of -* the supported hicolor pixel layouts. -* -****************************************************************************/ - #include "always.h" #include diff --git a/code/voxlib.cpp b/code/voxlib.cpp index f6186c05..d143ba3b 100644 --- a/code/voxlib.cpp +++ b/code/voxlib.cpp @@ -86,7 +86,7 @@ const Vector3 *VoxelNormalTables[] = }; -// warning C4305: 'argument' : truncation from 'const double' to 'float' +/// warning C4305: 'argument' : truncation from 'const double' to 'float' #pragma warning(disable : 4305) float VoxelNormals1[][3] = { @@ -837,14 +837,17 @@ void VoxelLibrary::Render_Object(VoxelRenderStruct & voxel, Vector3 & center) /// The projection, stride and voxel data setup for this object. static void __cdecl _voxel_draw_shadow(VoxelFuncArgumentStruct * state) { + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->EndOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -857,11 +860,13 @@ static void __cdecl _voxel_draw_shadow(VoxelFuncArgumentStruct * state) VoxelDrawBuffer[buffer_index + 1] = color_index; } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -924,24 +929,33 @@ void VoxelLibrary::Render_Shadow(VoxelShadowRenderStruct & voxel, Vector3 & cent /// void VoxelLibrary::Compute_Bounding_Box(void) { + /// Compute the coordinates of the eight corners of the bounding box. for (unsigned i = 0; i < LayerInfoCount; i++) { LayerInfoStruct &layerinfo = LayerInfos[i]; + // +x +y -z layerinfo.BoxCorner[VOXEL_BOUNDS_BFR] = Vector3(+layerinfo.XSize / 2.0f, +layerinfo.YSize / 2.0f, -layerinfo.ZSize / 2.0f); + // +x -y -z layerinfo.BoxCorner[VOXEL_BOUNDS_BBR] = Vector3(+layerinfo.XSize / 2.0f, -layerinfo.YSize / 2.0f, -layerinfo.ZSize / 2.0f); + // -x -y -z layerinfo.BoxCorner[VOXEL_BOUNDS_BBL] = Vector3(-layerinfo.XSize / 2.0f, -layerinfo.YSize / 2.0f, -layerinfo.ZSize / 2.0f); + // -x +y -z layerinfo.BoxCorner[VOXEL_BOUNDS_BFL] = Vector3(-layerinfo.XSize / 2.0f, +layerinfo.YSize / 2.0f, -layerinfo.ZSize / 2.0f); + // +x +y +z layerinfo.BoxCorner[VOXEL_BOUNDS_TFR] = Vector3(+layerinfo.XSize / 2.0f, +layerinfo.YSize / 2.0f, +layerinfo.ZSize / 2.0f); + // +x -y +z layerinfo.BoxCorner[VOXEL_BOUNDS_TBR] = Vector3(+layerinfo.XSize / 2.0f, -layerinfo.YSize / 2.0f, +layerinfo.ZSize / 2.0f); + // -x -y +z layerinfo.BoxCorner[VOXEL_BOUNDS_TBL] = Vector3(-layerinfo.XSize / 2.0f, -layerinfo.YSize / 2.0f, +layerinfo.ZSize / 2.0f); + // -x +y +z layerinfo.BoxCorner[VOXEL_BOUNDS_TFL] = Vector3(-layerinfo.XSize / 2.0f, +layerinfo.YSize / 2.0f, +layerinfo.ZSize / 2.0f); } } -// The three variants that follow build the same table and differ only in whether each -// store goes through the local reference or names VoxelPixelDeltaTable outright. Which -// variant a drawer calls is deliberate; do not merge them. +/// The three variants that follow build the same table and differ only in whether each +/// store goes through the local reference or names VoxelPixelDeltaTable outright. Which +/// variant a drawer calls is deliberate; do not merge them. /// /// Fills in the voxel projection delta table. @@ -1027,14 +1041,17 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->StartOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1044,7 +1061,7 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1077,7 +1094,8 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) */ ptr++; - // A voxel covers two buffer bytes, so the colour goes down twice. + /// Compute buffer index and write color. A voxel covers two + /// buffer bytes, so the colour goes down twice. unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); VoxelDrawBuffer[buffer_index] = color_index; VoxelDrawBuffer[buffer_index + 1] = color_index; @@ -1093,11 +1111,13 @@ void __cdecl Draw_Voxel_Regular_Normals(VoxelFuncArgumentStruct * state) } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1120,14 +1140,17 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table1(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->EndOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1137,7 +1160,7 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1159,7 +1182,8 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr--; - // A voxel covers two buffer bytes, so the colour goes down twice. + /// Compute buffer index and write color. A voxel covers two + /// buffer bytes, so the colour goes down twice. unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); VoxelDrawBuffer[buffer_index] = color_index; VoxelDrawBuffer[buffer_index + 1] = color_index; @@ -1186,11 +1210,13 @@ void __cdecl Draw_Voxel_Reverse_Normals(VoxelFuncArgumentStruct * state) } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1213,16 +1239,19 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table3(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -1233,7 +1262,7 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1268,6 +1297,7 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer(VoxelFuncArgumentStruct * state) */ ptr++; + /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { VoxelDrawZBuffer[buffer_index] = (pixel_z >> 8); @@ -1288,12 +1318,14 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer(VoxelFuncArgumentStruct * state) } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -1317,16 +1349,19 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -1337,7 +1372,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1365,6 +1400,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer(VoxelFuncArgumentStruct * state) value = *ptr; ptr--; + /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { VoxelDrawZBuffer[buffer_index] = (pixel_z >> 8); @@ -1397,12 +1433,14 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer(VoxelFuncArgumentStruct * state) } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -1426,14 +1464,17 @@ void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state */ Fill_Delta_Table1(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->StartOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1443,7 +1484,7 @@ void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1478,6 +1519,7 @@ void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state unsigned char table_index = VoxelNormalTranslateTable[normal_index]; ptr++; + /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); color_index = VoxelPaletteTranslateTable[table_index][color_index]; @@ -1495,11 +1537,13 @@ void __cdecl Draw_Voxel_Regular_Normals_Lighting(VoxelFuncArgumentStruct * state } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1522,14 +1566,17 @@ void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state */ Fill_Delta_Table2(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->EndOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1539,7 +1586,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1563,6 +1610,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state unsigned char color_index = *ptr; ptr--; + /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); color_index = VoxelPaletteTranslateTable[table_index][color_index]; @@ -1591,11 +1639,13 @@ void __cdecl Draw_Voxel_Reverse_Normals_Lighting(VoxelFuncArgumentStruct * state } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1618,16 +1668,19 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct */ Fill_Delta_Table2(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -1638,7 +1691,7 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1661,6 +1714,7 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct remaining -= run_length; while (run_length) { + /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { @@ -1707,12 +1761,14 @@ void __cdecl Draw_Voxel_Regular_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -1736,16 +1792,19 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct */ Fill_Delta_Table1(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -1756,7 +1815,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1767,6 +1826,7 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct remaining -= run_length; while (run_length) { + /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { @@ -1826,12 +1886,14 @@ void __cdecl Draw_Voxel_Reverse_Normals_ZBuffer_Lighting(VoxelFuncArgumentStruct } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -1854,14 +1916,17 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table1(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->StartOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1871,7 +1936,7 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -1899,7 +1964,8 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr++; - // Unlike the shaded drawers, this one covers a single buffer byte per voxel. + /// Compute buffer index and write color. Unlike the shaded + /// drawers, this one covers a single buffer byte per voxel. VoxelDrawBuffer[(pixel_x >> 8) | (pixel_y & 0xFF00)] = color_index; pixel_x += state->TransformMatrix[3].I; @@ -1913,11 +1979,13 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -1939,14 +2007,17 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned int data_offset = ((unsigned int *)state->EndOffset)[state->StartIndex]; unsigned short column_start_x = pixel_x; @@ -1956,7 +2027,7 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -1973,7 +2044,8 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr--; - // Unlike the shaded drawers, this one covers a single buffer byte per voxel. + /// Compute buffer index and write color. Unlike the shaded + /// drawers, this one covers a single buffer byte per voxel. VoxelDrawBuffer[(pixel_x >> 8) | (pixel_y & 0xFF00)] = color_index; pixel_x += state->TransformMatrix[3].I; @@ -1998,11 +2070,13 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; state->StartIndex = state->StrideY + base_index; @@ -2025,16 +2099,19 @@ void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -2045,7 +2122,7 @@ void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { /* @@ -2075,6 +2152,7 @@ void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state) value = *ptr; ptr++; + /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { VoxelDrawZBuffer[buffer_index] = (pixel_z >> 8); @@ -2095,12 +2173,14 @@ void __cdecl Draw_Voxel_Regular_ZBuffer(VoxelFuncArgumentStruct * state) } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; @@ -2124,16 +2204,19 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state) */ Fill_Delta_Table2(state); + /// Set starting 2D projection position unsigned short pixel_x = state->TransformMatrix[0].I; unsigned short pixel_y = state->TransformMatrix[0].J; unsigned short pixel_z = state->TransformMatrix[0].K; + /// Iterate over voxel Y slices (rows) for (unsigned int y = 0; y < state->YSize; y++) { unsigned int base_index = state->StartIndex; unsigned short row_start_x = pixel_x; unsigned short row_start_y = pixel_y; unsigned short row_start_z = pixel_z; + /// Iterate over voxel X columns (within the current Y row) for (unsigned int x = 0; x < state->XSize; x++) { unsigned short column_start_x = pixel_x; unsigned short column_start_y = pixel_y; @@ -2144,7 +2227,7 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state) unsigned char * ptr = state->DataOffset + data_offset; unsigned int remaining = state->ZSize; - // Parse voxel run-length encoded data along Z axis + /// Parse voxel run-length encoded data along Z axis while (remaining) { // Byte 4 - run length(backward) @@ -2167,6 +2250,7 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state) value = *ptr; ptr--; + /// Compute buffer index and write color unsigned int buffer_index = (pixel_x >> 8) | (pixel_y & 0xFF00); if ((pixel_z >> 8) > VoxelDrawZBuffer[buffer_index]) { VoxelDrawZBuffer[buffer_index] = (pixel_z >> 8); @@ -2199,12 +2283,14 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state) } } + /// Advance to next voxel in X direction pixel_x = column_start_x + state->TransformMatrix[1].I; pixel_y = column_start_y + state->TransformMatrix[1].J; pixel_z = column_start_z + state->TransformMatrix[1].K; state->StartIndex = state->StrideX + state->StartIndex; } + /// Advance to next voxel row (Y direction) pixel_x = row_start_x + state->TransformMatrix[2].I; pixel_y = row_start_y + state->TransformMatrix[2].J; pixel_z = row_start_z + state->TransformMatrix[2].K; From 7a838559922afdfb6cfc359f212c387a1b677dac Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Thu, 3 Sep 2026 21:04:55 +0200 Subject: [PATCH 08/14] Correct the voxel drawer dispatch table comment --- code/voxlib.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/voxlib.cpp b/code/voxlib.cpp index d143ba3b..02e5a37a 100644 --- a/code/voxlib.cpp +++ b/code/voxlib.cpp @@ -38,8 +38,8 @@ void __cdecl Draw_Voxel_Reverse_ZBuffer(VoxelFuncArgumentStruct * state); /* * Indexed by the orientation's direction together with the depth buffer, lighting and normal - * type switches, which is why the last four entries repeat the four before them: the normal - * type does not change which drawer is wanted once lighting is off. + * type switches, which is why the last four entries repeat the four before them: a layer + * without normals has nothing to light, so lighting does not change which drawer is wanted. */ VoxelFuncPtr VoxelDrawFunctions[16] = { &Draw_Voxel_Regular_Normals, From f45fa044fdddd3974ed0b6535b04488077cb0012 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Thu, 3 Sep 2026 21:04:55 +0200 Subject: [PATCH 09/14] Fold the duplicated 655 brightening branch into one if/else --- code/colorops.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/colorops.cpp b/code/colorops.cpp index 144c3ed1..d3c34766 100644 --- a/code/colorops.cpp +++ b/code/colorops.cpp @@ -159,15 +159,12 @@ void Brighten_Color(std::uint8_t const * mulbuffer, std::uint16_t * colorbuffer, if (format.Mask == ALTERNATE_MARKER) { result |= (greenpart & ALTERNATE_MARKER); + result |= redpart; } else { result |= greenpart; result |= (redpart & (format.Mask * 256)); } - if (format.Mask == ALTERNATE_MARKER) { - result |= redpart; - } - *color = (std::uint16_t)result; } From ec17648e01c67fd6b950193760f1925cda6e82a6 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Thu, 3 Sep 2026 21:04:56 +0200 Subject: [PATCH 10/14] Fill the normal lookup in the voxel drawing test --- tests/voxeldraw/voxeldraw.cpp | 9 ++++ tests/voxeldraw/voxelgolden.h | 96 +++++++++++++++++------------------ 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/tests/voxeldraw/voxeldraw.cpp b/tests/voxeldraw/voxeldraw.cpp index ea8e99f9..02b4b73e 100644 --- a/tests/voxeldraw/voxeldraw.cpp +++ b/tests/voxeldraw/voxeldraw.cpp @@ -173,6 +173,15 @@ void Build_Layer(unsigned int seed, int columns, int zsize, bool withnormals) VoxelPaletteTranslateTable[i][j] = (unsigned char)(Next_Random() & 0xFF); } } + + /* + * The shaded drawers pick a palette lookup row through this table, and the engine only + * ever puts a row number in it. Left zeroed it holds every voxel to row zero, which is + * the one case that would not tell a wrong lookup apart from a right one. + */ + for (int i = 0; i < VOXEL_PALETTE_SIZE; i++) { + VoxelNormalTranslateTable[i] = (unsigned char)(Next_Random() % MAX_PALETTE_LOOKUP_ENTRIES); + } } diff --git a/tests/voxeldraw/voxelgolden.h b/tests/voxeldraw/voxelgolden.h index af3f4d9e..41a1e1b5 100644 --- a/tests/voxeldraw/voxelgolden.h +++ b/tests/voxeldraw/voxelgolden.h @@ -70,54 +70,54 @@ static VoxelGoldenCase const VoxelGoldenCases[] = { {1, 384524u, 13050037680469517880ULL}, {1, 392443u, 9010391954831812739ULL}, {1, 400362u, 6942504870830098237ULL}, - {2, 408281u, 15798523031825813403ULL}, - {2, 416200u, 4507558737198793848ULL}, - {2, 424119u, 3851442749804437763ULL}, - {2, 432038u, 930039072865289532ULL}, - {2, 439957u, 14918691864484818114ULL}, - {2, 447876u, 1900814372412917523ULL}, - {2, 455795u, 9880610814969945598ULL}, - {2, 463714u, 12235921528745917133ULL}, - {2, 471633u, 17295491051951213915ULL}, - {2, 479552u, 8208964221764546070ULL}, - {2, 487471u, 15498567043124049416ULL}, - {2, 495390u, 11601304743621742993ULL}, - {2, 503309u, 13668221661727899355ULL}, - {2, 511228u, 8056635900584925629ULL}, - {2, 519147u, 2371813117170145389ULL}, - {2, 527066u, 11631430866345469306ULL}, - {2, 534985u, 3391000685292444630ULL}, - {2, 542904u, 1748974867776887855ULL}, - {2, 550823u, 12245671744384124113ULL}, - {2, 558742u, 14093335007620427588ULL}, - {2, 566661u, 1834971198173119818ULL}, - {2, 574580u, 11489914551042742038ULL}, - {2, 582499u, 11144311815646134855ULL}, - {2, 590418u, 6836879586511554304ULL}, - {3, 598337u, 1976035810807648333ULL}, - {3, 606256u, 883352253650328485ULL}, - {3, 614175u, 15160697399241641046ULL}, - {3, 622094u, 18205160147392533888ULL}, - {3, 630013u, 14713795521886969930ULL}, - {3, 637932u, 11922145548072268503ULL}, - {3, 645851u, 7792075245259396222ULL}, - {3, 653770u, 8258093120125759069ULL}, - {3, 661689u, 18415915043351740624ULL}, - {3, 669608u, 6976820877669932813ULL}, - {3, 677527u, 11393741950045336747ULL}, - {3, 685446u, 7013445700322398ULL}, - {3, 693365u, 16301890081953396848ULL}, - {3, 701284u, 2884016264197242965ULL}, - {3, 709203u, 13109705519595437632ULL}, - {3, 717122u, 9038234598152107521ULL}, - {3, 725041u, 18120218201080976346ULL}, - {3, 732960u, 16154636395797325481ULL}, - {3, 740879u, 11006938371435845325ULL}, - {3, 748798u, 5101920956829682532ULL}, - {3, 756717u, 8748102682002764481ULL}, - {3, 764636u, 11659063084790268686ULL}, - {3, 772555u, 2655796341723522167ULL}, - {3, 780474u, 725836304033682059ULL}, + {2, 408281u, 12117523108316906693ULL}, + {2, 416200u, 2860773480838482206ULL}, + {2, 424119u, 16795950920314261845ULL}, + {2, 432038u, 16269504432944727866ULL}, + {2, 439957u, 5759255697188250555ULL}, + {2, 447876u, 3905793808348731109ULL}, + {2, 455795u, 11958563865995725522ULL}, + {2, 463714u, 7905260979237486147ULL}, + {2, 471633u, 6596126725648556101ULL}, + {2, 479552u, 9396465740447231265ULL}, + {2, 487471u, 3021707311810065007ULL}, + {2, 495390u, 12608520186210480583ULL}, + {2, 503309u, 7168738705722408131ULL}, + {2, 511228u, 16415847505290227908ULL}, + {2, 519147u, 14850527117861014473ULL}, + {2, 527066u, 2224878929674075414ULL}, + {2, 534985u, 3526068071759325697ULL}, + {2, 542904u, 7468107996873568077ULL}, + {2, 550823u, 2552806796036422836ULL}, + {2, 558742u, 10047178558152115580ULL}, + {2, 566661u, 15609928606204843882ULL}, + {2, 574580u, 3130933050453705124ULL}, + {2, 582499u, 14337216876066503889ULL}, + {2, 590418u, 10456759002404203783ULL}, + {3, 598337u, 6351919810774857422ULL}, + {3, 606256u, 13915808430987595008ULL}, + {3, 614175u, 17903783046195662788ULL}, + {3, 622094u, 4914405847178468645ULL}, + {3, 630013u, 333711237430617735ULL}, + {3, 637932u, 3463009737098995480ULL}, + {3, 645851u, 18173791062746827977ULL}, + {3, 653770u, 11159028218079293990ULL}, + {3, 661689u, 11850058907912138592ULL}, + {3, 669608u, 2196087987858281170ULL}, + {3, 677527u, 17000547845918035067ULL}, + {3, 685446u, 15682288714728306616ULL}, + {3, 693365u, 12264100888018795473ULL}, + {3, 701284u, 11491390033144584866ULL}, + {3, 709203u, 11496496764390394209ULL}, + {3, 717122u, 15575541066751950758ULL}, + {3, 725041u, 2084845422949980028ULL}, + {3, 732960u, 376904464664531940ULL}, + {3, 740879u, 11946234243501752857ULL}, + {3, 748798u, 12248491227993063803ULL}, + {3, 756717u, 3197674996467238327ULL}, + {3, 764636u, 6995839700847232548ULL}, + {3, 772555u, 5309075241543235626ULL}, + {3, 780474u, 10479909650629901107ULL}, {4, 788393u, 17319385156311552112ULL}, {4, 796312u, 16114144959221699025ULL}, {4, 804231u, 10340858242751730055ULL}, From 07d3f77720e56992ba9d8c38cf0bca80f896f908 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Thu, 3 Sep 2026 21:04:56 +0200 Subject: [PATCH 11/14] Record only the table-driven brightening vectors --- tests/colorops/colorgolden.h | 99 +++++++++++---------------------- tests/colorops/coloropstest.cpp | 5 -- 2 files changed, 33 insertions(+), 71 deletions(-) diff --git a/tests/colorops/colorgolden.h b/tests/colorops/colorgolden.h index fdd1a910..3e4d8a34 100644 --- a/tests/colorops/colorgolden.h +++ b/tests/colorops/colorgolden.h @@ -49,7 +49,6 @@ static int const AdjustGoldenCaseCount = 20; struct BrightenGoldenCase { int Mode; - int Mmx; int Width; int Height; unsigned int Seed; @@ -57,70 +56,38 @@ struct BrightenGoldenCase { }; static BrightenGoldenCase const BrightenGoldenCases[] = { - {0, 0, 1, 1, 174490u, 9683954061780082186ULL}, - {0, 0, 2, 1, 182409u, 3585589939020540445ULL}, - {0, 0, 7, 3, 190328u, 12646124570177522196ULL}, - {0, 0, 16, 4, 198247u, 8855089449368412364ULL}, - {0, 0, 33, 9, 206166u, 4161396504343120247ULL}, - {0, 0, 64, 16, 214085u, 7491337042742393889ULL}, - {0, 0, 128, 32, 222004u, 1562462105826136594ULL}, - {0, 0, 255, 64, 229923u, 12977303894793765084ULL}, - {0, 1, 1, 1, 237842u, 2534684662198146892ULL}, - {0, 1, 2, 1, 245761u, 9679803194961330382ULL}, - {0, 1, 7, 3, 253680u, 2549577378279256583ULL}, - {0, 1, 16, 4, 261599u, 11676825973235883859ULL}, - {0, 1, 33, 9, 269518u, 13545447451985782494ULL}, - {0, 1, 64, 16, 277437u, 4102005335375077591ULL}, - {0, 1, 128, 32, 285356u, 3889344650472255677ULL}, - {0, 1, 255, 64, 293275u, 3297543697270025883ULL}, - {1, 0, 1, 1, 301194u, 13186354609198225149ULL}, - {1, 0, 2, 1, 309113u, 13814059303084228345ULL}, - {1, 0, 7, 3, 317032u, 10720627840618582556ULL}, - {1, 0, 16, 4, 324951u, 18012041115974557435ULL}, - {1, 0, 33, 9, 332870u, 7090443837710868316ULL}, - {1, 0, 64, 16, 340789u, 7935162482590007511ULL}, - {1, 0, 128, 32, 348708u, 16754602968852868577ULL}, - {1, 0, 255, 64, 356627u, 11578321534074525250ULL}, - {1, 1, 1, 1, 364546u, 10427039056597764142ULL}, - {1, 1, 2, 1, 372465u, 1748292752117078850ULL}, - {1, 1, 7, 3, 380384u, 10317547240677326599ULL}, - {1, 1, 16, 4, 388303u, 16604617947182860757ULL}, - {1, 1, 33, 9, 396222u, 1318537032546736748ULL}, - {1, 1, 64, 16, 404141u, 9229413794311576209ULL}, - {1, 1, 128, 32, 412060u, 7340557553286926667ULL}, - {1, 1, 255, 64, 419979u, 5071078941017253528ULL}, - {2, 0, 1, 1, 427898u, 10459444610915521759ULL}, - {2, 0, 2, 1, 435817u, 9809152111208362860ULL}, - {2, 0, 7, 3, 443736u, 5974842822965084410ULL}, - {2, 0, 16, 4, 451655u, 14016269938534619012ULL}, - {2, 0, 33, 9, 459574u, 11686188751530981124ULL}, - {2, 0, 64, 16, 467493u, 16824327894963774702ULL}, - {2, 0, 128, 32, 475412u, 831560034207278086ULL}, - {2, 0, 255, 64, 483331u, 10597710443419274145ULL}, - {2, 1, 1, 1, 491250u, 8479100877978498426ULL}, - {2, 1, 2, 1, 499169u, 7481949699832809259ULL}, - {2, 1, 7, 3, 507088u, 16607636731006922296ULL}, - {2, 1, 16, 4, 515007u, 6405581235097048851ULL}, - {2, 1, 33, 9, 522926u, 822099569615870640ULL}, - {2, 1, 64, 16, 530845u, 8266273084601642906ULL}, - {2, 1, 128, 32, 538764u, 8535626501608830796ULL}, - {2, 1, 255, 64, 546683u, 3737545516508015044ULL}, - {3, 0, 1, 1, 554602u, 3476118273324028887ULL}, - {3, 0, 2, 1, 562521u, 3460303321212174411ULL}, - {3, 0, 7, 3, 570440u, 5507246755901068217ULL}, - {3, 0, 16, 4, 578359u, 2761380345813287195ULL}, - {3, 0, 33, 9, 586278u, 14881774169913704698ULL}, - {3, 0, 64, 16, 594197u, 13329692175776703259ULL}, - {3, 0, 128, 32, 602116u, 16441757303667149227ULL}, - {3, 0, 255, 64, 610035u, 2060866494282096795ULL}, - {3, 1, 1, 1, 617954u, 11405787290677921704ULL}, - {3, 1, 2, 1, 625873u, 6279770659411831877ULL}, - {3, 1, 7, 3, 633792u, 10521531452208876928ULL}, - {3, 1, 16, 4, 641711u, 14797326666873277565ULL}, - {3, 1, 33, 9, 649630u, 7304885447097531915ULL}, - {3, 1, 64, 16, 657549u, 15330689263602870827ULL}, - {3, 1, 128, 32, 665468u, 10892574876935284254ULL}, - {3, 1, 255, 64, 673387u, 10579957447657776596ULL}, + {0, 1, 1, 174490u, 8547899790972384037ULL}, + {0, 2, 1, 182409u, 9033303418023310041ULL}, + {0, 7, 3, 190328u, 6143991159647516153ULL}, + {0, 16, 4, 198247u, 6630761853223497632ULL}, + {0, 33, 9, 206166u, 622415682941848259ULL}, + {0, 64, 16, 214085u, 14245264095721699130ULL}, + {0, 128, 32, 222004u, 3535184424732130215ULL}, + {0, 255, 64, 229923u, 11059887967966512383ULL}, + {1, 1, 1, 237842u, 8952510067782069416ULL}, + {1, 2, 1, 245761u, 18341618508397812069ULL}, + {1, 7, 3, 253680u, 17136944462687638323ULL}, + {1, 16, 4, 261599u, 1329247239310315574ULL}, + {1, 33, 9, 269518u, 9097168305540845299ULL}, + {1, 64, 16, 277437u, 9011678934784903602ULL}, + {1, 128, 32, 285356u, 516312214522963662ULL}, + {1, 255, 64, 293275u, 16586913180682861867ULL}, + {2, 1, 1, 301194u, 1854941125446135212ULL}, + {2, 2, 1, 309113u, 8166626354983351891ULL}, + {2, 7, 3, 317032u, 3566864742387281003ULL}, + {2, 16, 4, 324951u, 13038710579393311255ULL}, + {2, 33, 9, 332870u, 9886918198976680958ULL}, + {2, 64, 16, 340789u, 15331910246435108890ULL}, + {2, 128, 32, 348708u, 9794244924404923692ULL}, + {2, 255, 64, 356627u, 13922501480171177141ULL}, + {3, 1, 1, 364546u, 13913672783145744802ULL}, + {3, 2, 1, 372465u, 14314246977719733954ULL}, + {3, 7, 3, 380384u, 11543133916950861488ULL}, + {3, 16, 4, 388303u, 3167944849081864697ULL}, + {3, 33, 9, 396222u, 6021446366408612999ULL}, + {3, 64, 16, 404141u, 1062804387441418589ULL}, + {3, 128, 32, 412060u, 3865748224324302223ULL}, + {3, 255, 64, 419979u, 5307043396739084831ULL}, }; -static int const BrightenGoldenCaseCount = 64; +static int const BrightenGoldenCaseCount = 32; diff --git a/tests/colorops/coloropstest.cpp b/tests/colorops/coloropstest.cpp index c4370411..dbba0e08 100644 --- a/tests/colorops/coloropstest.cpp +++ b/tests/colorops/coloropstest.cpp @@ -130,11 +130,6 @@ int main(void) for (int i = 0; i < BrightenGoldenCaseCount; i++) { BrightenGoldenCase const & test = BrightenGoldenCases[i]; - // The non-MMX vectors record a path colorops.cpp no longer has. - if (test.Mmx == 0) { - continue; - } - Seed = test.Seed; for (int j = 0; j < 256 * 256; j++) { From 00610f2d2d61b7f4582239f1b8a4d8e49a58fba1 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Thu, 3 Sep 2026 21:04:56 +0200 Subject: [PATCH 12/14] Name the spot light colour table for what it holds --- code/ovrlight.cpp | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/code/ovrlight.cpp b/code/ovrlight.cpp index c7fa5f14..6e1b6fda 100644 --- a/code/ovrlight.cpp +++ b/code/ovrlight.cpp @@ -18,7 +18,6 @@ #include "_tactica.h" #include "bsurface.h" #include "dsurface.h" -#include "getcpu.h" #include "globals.h" #include "rules.h" #include "scenario.h" @@ -29,9 +28,8 @@ DynamicVectorClass SpotLights; -int SpotLightDontUseMMX = false; int SpotLightColorMode = -1; -int *SpotLightMMXBuffer; +int *SpotLightColorTable; BSurface *SpotLightSurfaces[SpotLightClass::SPOTLIGHT_SURFACE_COUNT + SpotLightClass::SPOTLIGHT_EXTRA_SURFACE_COUNT]; extern "C" { @@ -108,7 +106,7 @@ void SpotLightClass::Update_All(void) /// /// Performs the one time initialization of the spot light system. /// This routine builds the brightness ramp surfaces that every spot light is drawn from, -/// and prepares the hicolor acceleration table when the processor can make use of it. +/// and the table the brightening routines read a pixel's channels out of. /// /// It is safe to call this routine again after the video mode changes -- the /// artwork is built only once, but the color mode is picked up afresh each time. @@ -155,15 +153,12 @@ void SpotLightClass::One_Time(void) } SpotLightColorMode = DSurface::Get_Primary_Color_Mode(); - int cpu_type = PROC_PENTIUM_PRO; - bool mmx = false; - Get_CPU_Type(cpu_type, mmx); - if (mmx && SpotLightMMXBuffer == NULL) { - SpotLightMMXBuffer = new int[65536]; + if (SpotLightColorTable == NULL) { + SpotLightColorTable = new int[65536]; for (int color = 0; color < 65536; color++) { RGBClass rgb = DSurface::Deconstruct_Hicolor_Pixel(color); - SpotLightMMXBuffer[color] = (rgb.Get_Red() << 16) | (rgb.Get_Green() << 8) | (rgb.Get_Blue()); + SpotLightColorTable[color] = (rgb.Get_Red() << 16) | (rgb.Get_Green() << 8) | (rgb.Get_Blue()); } } } @@ -172,13 +167,13 @@ void SpotLightClass::One_Time(void) /// /// Frees the artwork the spot lights draw with. /// This routine is called during shutdown to release the brightness ramp surfaces and the -/// hicolor acceleration table that One_Time built. +/// hicolor lookup table that One_Time built. /// void SpotLightClass::Clear_All(void) { - if (SpotLightMMXBuffer != NULL) { - delete [] SpotLightMMXBuffer; - SpotLightMMXBuffer = NULL; + if (SpotLightColorTable != NULL) { + delete [] SpotLightColorTable; + SpotLightColorTable = NULL; } for (int i = 0; i < SPOTLIGHT_SURFACE_COUNT + SPOTLIGHT_EXTRA_SURFACE_COUNT; i++) { delete SpotLightSurfaces[i]; @@ -235,23 +230,23 @@ void SpotLightClass::Draw_It(void) unsigned char *sptr_row = sptr; unsigned short *dptr_row = dptr; - if (SpotLightDontUseMMX != 1 && SpotLightMMXBuffer != NULL) { + if (SpotLightColorTable != NULL) { switch (SpotLightColorMode) { case COLORMODE_555: - Brighten_Color_555(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); + Brighten_Color_555(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightColorTable); break; case COLORMODE_556: - Brighten_Color_556(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); + Brighten_Color_556(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightColorTable); break; case COLORMODE_565: - Brighten_Color_565(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); + Brighten_Color_565(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightColorTable); break; case COLORMODE_655: - Brighten_Color_655(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightMMXBuffer); + Brighten_Color_655(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightColorTable); break; default: From ec38053b8f0a72cc24a03909793a116648fb8915 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Thu, 3 Sep 2026 21:04:56 +0200 Subject: [PATCH 13/14] Remove MMX detection --- code/getcpu.cpp | 28 ++++++----------------- code/getcpu.h | 12 ++-------- code/init.cpp | 3 +-- code/milsectmr.cpp | 3 +-- code/scenario.cpp | 3 +-- code/syncreport.cpp | 3 +-- manual/changes/cpu-feature-detection.md | 21 ++++++++--------- tests/cpudetect/cpudetect.cpp | 30 +++++-------------------- 8 files changed, 29 insertions(+), 74 deletions(-) diff --git a/code/getcpu.cpp b/code/getcpu.cpp index 456c1b32..6f9ac4ae 100644 --- a/code/getcpu.cpp +++ b/code/getcpu.cpp @@ -51,7 +51,6 @@ * * * * * INPUT: int - reference to cpu type * - * bool - reference to mmx availability flag * * char* - ptr to buffer to receive chip vendor info * * int - length of above buffer * * * @@ -65,15 +64,12 @@ extern "C" { -char UseCMOV = 1; -char HasCMOV = 1; -char UseMMX = 1; char CPUType = 0; /* - * Filled in by Detect_MMX_Availability from CPUID leaf 0. The buffer holds the twelve - * vendor characters, the separating space the original wrote after them, and the - * terminator Get_CPU_Type copies up to. + * Filled in by CPU_Id from CPUID leaf 0. The buffer holds the twelve vendor characters, + * the separating space the original wrote after them, and the terminator Get_CPU_Type + * copies up to. */ char VendorID[20] = "Not available"; @@ -81,13 +77,9 @@ char VendorID[20] = "Not available"; /// -/// Records the processor family in CPUType and the vendor in VendorID, and reports MMX -/// support. The supported minimum hardware (SSE2, so a Pentium 4 or Athlon 64 onward) always -/// has MMX, so this always sets UseMMX and returns true rather than reading the CPUID -/// feature bit. +/// Records the processor family in CPUType and the vendor in VendorID. /// -/// bool; always true on the supported minimum hardware. -bool __cdecl Detect_MMX_Availability(void) +void __cdecl CPU_Id(void) { int regs[4]; @@ -108,18 +100,12 @@ bool __cdecl Detect_MMX_Availability(void) } CPUType = cputype; - - UseMMX = 1; - return(true); } -void Get_CPU_Type(int & cpu_type, bool & mmx, char * vendor_id, int vendor_id_length) +void Get_CPU_Type(int & cpu_type, char * vendor_id, int vendor_id_length) { - /* - ** Call the asm CPU detection code - */ - mmx = Detect_MMX_Availability(); + CPU_Id(); /* ** Return the promised results diff --git a/code/getcpu.h b/code/getcpu.h index 6ee8f1a2..286a276a 100644 --- a/code/getcpu.h +++ b/code/getcpu.h @@ -13,21 +13,13 @@ #pragma once -void Get_CPU_Type(int & cpu_type, bool & mmx, char * vendor_id = 0, int vendor_id_length = 0); +void Get_CPU_Type(int & cpu_type, char * vendor_id = 0, int vendor_id_length = 0); extern "C" { - bool __cdecl Detect_MMX_Availability(void); + void __cdecl CPU_Id(void); extern char CPUType; extern char VendorID[]; - - /* - * Fixed true rather than probed: the supported minimum hardware (SSE2, so a Pentium 4 or - * Athlon 64 onward) always has CMOV and MMX. - */ - extern char UseCMOV; - extern char HasCMOV; - extern char UseMMX; } // Processor family constants. Get_CPU_Type reports the CPUID base family through its diff --git a/code/init.cpp b/code/init.cpp index 810bf5c0..8ea908fa 100644 --- a/code/init.cpp +++ b/code/init.cpp @@ -3023,10 +3023,9 @@ BOOL CALLBACK Version_Dialog_Proc(HWND window, UINT message, WPARAM wparam, LPAR // The braces keep the 'case' label from jumping over these initializations. { int cpu_type = 5; - bool mmx = false; char vendor[32]; vendor[0] = '\0'; - Get_CPU_Type(cpu_type, mmx, vendor, sizeof(vendor) - 1); + Get_CPU_Type(cpu_type, vendor, sizeof(vendor) - 1); sprintf(buffer, "CPU vendor: %s", vendor); ListBox_AddString(handle, buffer); diff --git a/code/milsectmr.cpp b/code/milsectmr.cpp index ccc29ab1..f77953f9 100644 --- a/code/milsectmr.cpp +++ b/code/milsectmr.cpp @@ -77,10 +77,9 @@ MillisecondTimerClass::~MillisecondTimerClass(void) MillisecondTimerClass::operator double () const { static int cpu_type = -1; - static bool has_mmx = false; if (cpu_type == -1) { - Get_CPU_Type(cpu_type, has_mmx, NULL, 0); + Get_CPU_Type(cpu_type, NULL, 0); } /// On extremely old CPUs (80486 and older) the TSC and rdtsc instruction don't exist. if (Frequency != 1.0 && cpu_type > 4) { diff --git a/code/scenario.cpp b/code/scenario.cpp index ae7da335..a0fa8e42 100644 --- a/code/scenario.cpp +++ b/code/scenario.cpp @@ -3738,11 +3738,10 @@ int Adjust_To_CPU_Timing(int time) static const double TIME_SCALE = 200; int cpu_type; - bool mmx; int speed = 0; - Get_CPU_Type(cpu_type, mmx, NULL, 0); + Get_CPU_Type(cpu_type, NULL, 0); if (cpu_type > PROC_PENTIUM_PRO) { time = (int)(time * P_SIX_TWEAK); diff --git a/code/syncreport.cpp b/code/syncreport.cpp index 5835cf79..626ffbf2 100644 --- a/code/syncreport.cpp +++ b/code/syncreport.cpp @@ -237,10 +237,9 @@ void Print_CRCs(EventClass const * events, int count, unsigned const * crc_ring, fprintf(fp, "FPU control word: %x\n", _controlfp(0, 0)); int cpu_type = PROC_PENTIUM_PRO; - bool mmx = false; char vendor[32]; vendor[0] = '\0'; - Get_CPU_Type(cpu_type, mmx, vendor, sizeof(vendor) - 1); + Get_CPU_Type(cpu_type, vendor, sizeof(vendor) - 1); fprintf(fp, "CPU vendor: %s\r\n", vendor); fprintf(fp, "Frames: %d\n", Frame); diff --git a/manual/changes/cpu-feature-detection.md b/manual/changes/cpu-feature-detection.md index 1e3dcd5f..0cb7e00d 100644 --- a/manual/changes/cpu-feature-detection.md +++ b/manual/changes/cpu-feature-detection.md @@ -1,20 +1,21 @@ --- -title: Assume MMX and CMOV on the supported minimum hardware +title: Remove MMX and CMOV detection category: internal release: 0.2.0 breaking: true migration: -- Remove any code that calls `Detect_CMOV_Availability` or `Processor`; both have been removed. -- Treat `UseMMX`, `UseCMOV`, and `HasCMOV` as fixed-true constants rather than runtime-detected flags. +- Remove any code that calls `Detect_MMX_Availability`, `Detect_CMOV_Availability`, or `Processor`; all have been removed. +- Remove any use of `UseMMX`, `UseCMOV`, and `HasCMOV`; the flags have been removed along with the assembly that read them. +- Drop the MMX flag argument from `Get_CPU_Type` calls; the parameter is gone. targets: [] credit: [tinix0] --- -OpenTS no longer asks the processor at startup whether it supports MMX and CMOV, and assumes -both. This formalizes the minimum hardware OpenTS already requires — SSE2, so a Pentium 4 or -Athlon 64 onward — which always carries MMX and CMOV. +OpenTS no longer asks the processor whether it supports MMX or CMOV. This formalizes the +minimum hardware OpenTS already requires — SSE2, so a Pentium 4 or Athlon 64 onward — which +always carries both. -A machine below that minimum was never covered by a build claim. It previously took a slower -path through the palette-fade routines and now executes an MMX or CMOV instruction the -processor does not have. The processor family CPUID reports is still read and returned through -`Get_CPU_Type` and the `CPUType` global. +A machine below that minimum was never covered by a build claim. The routines the flags +selected between are C++ now and take one path on every processor, so neither the flags nor the +detection that set them remain. The processor family and vendor CPUID reports are still read +and returned through `Get_CPU_Type` and the `CPUType` and `VendorID` globals. diff --git a/tests/cpudetect/cpudetect.cpp b/tests/cpudetect/cpudetect.cpp index e0f219fe..c0f06013 100644 --- a/tests/cpudetect/cpudetect.cpp +++ b/tests/cpudetect/cpudetect.cpp @@ -9,8 +9,7 @@ // Checks the processor detection in getcpu.cpp against CPUID read directly here. The // detection used to be hand-written assembly, so the point is to confirm the C++ reports the -// same family and vendor the instruction does, and that MMX and CMOV are reported available -// unconditionally, as required by the supported minimum hardware. Needs no game data. +// same family and vendor the instruction does. Needs no game data. #include @@ -48,13 +47,6 @@ int Reference_Family(void) } -int Reference_Feature_Edx(void) -{ - int regs[4]; - __cpuid(regs, 1); - return(regs[3]); -} - } // namespace @@ -73,23 +65,21 @@ int main(void) Check(maxleaf >= 1, "CPUID reports leaf 1"); int const family = Reference_Family(); - int const edx = Reference_Feature_Edx(); - std::printf("Reported vendor '%s', family %d, feature EDX %08X\n\n", vendor, family, (unsigned int)edx); + std::printf("Reported vendor '%s', family %d\n\n", vendor, family); int cpu_type = -1; - bool mmx = false; char reported[64]; std::memset(reported, 0, sizeof(reported)); - Get_CPU_Type(cpu_type, mmx, reported, sizeof(reported) - 1); + Get_CPU_Type(cpu_type, reported, sizeof(reported) - 1); Check(cpu_type == family, "Get_CPU_Type family matches CPUID"); Check(CPUType == (char)family, "CPUType global matches CPUID"); /* - * Detect_MMX_Availability writes the twelve vendor characters and then a space, so the - * buffer Get_CPU_Type copies out is the vendor followed by that separator. + * CPU_Id writes the twelve vendor characters and then a space, so the buffer + * Get_CPU_Type copies out is the vendor followed by that separator. */ char expected[16]; std::memcpy(expected, vendor, 12); @@ -97,16 +87,6 @@ int main(void) expected[13] = '\0'; Check(std::strcmp(reported, expected) == 0, "Vendor string matches CPUID"); - /* - * The supported minimum hardware (SSE2, so a Pentium 4 or Athlon 64 onward) always carries - * MMX and CMOV, so detection reports both available unconditionally rather than reading - * the CPUID feature bits. - */ - Check(mmx, "Get_CPU_Type reports MMX available"); - Check(UseMMX != 0, "UseMMX global reports available"); - Check(HasCMOV != 0, "HasCMOV global reports available"); - Check(UseCMOV != 0, "UseCMOV global reports available"); - /* * The clock accumulator only ever counts up, so a later read cannot be the smaller of * the two once both halves are put back together. From 63f778a34e5d8efb12cbb4459ba7bb2870564ed8 Mon Sep 17 00:00:00 2001 From: Jakub Vesely <1251980+tinix0@users.noreply.github.com> Date: Thu, 3 Sep 2026 21:06:10 +0200 Subject: [PATCH 14/14] Register the syncrec test again --- tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d7a35e0d..003214f4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,5 +5,6 @@ add_subdirectory(logstress) add_subdirectory(netpacket) add_subdirectory(sosparity) add_subdirectory(spawner) +add_subdirectory(syncrec) add_subdirectory(colorops) add_subdirectory(voxeldraw)