diff --git a/code/colorops.cpp b/code/colorops.cpp new file mode 100644 index 00000000..d3c34766 --- /dev/null +++ b/code/colorops.cpp @@ -0,0 +1,232 @@ +/******************************************************************************* + * 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. + ******************************************************************************/ + +#include "always.h" + +#include + +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 { + 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}; +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. +/// std::uint32_t; The scaled channel, at most 255. +inline std::uint32_t Scale_Channel(std::uint32_t channel, std::uint32_t scale) +{ + std::uint32_t const scaled = (std::uint32_t)(channel * scale) >> 16; + return((scaled > 255) ? 255 : scaled); +} + + +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 (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]; + + 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 = (std::uint32_t)red; + greenscale = (std::uint32_t)green; + bluescale = (std::uint32_t)blue; + } + + 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] = (std::uint16_t)(((outr & format.RedMask) << format.RedShift) + | ((outg & format.GreenMask) << format.GreenShift) + | ((outb & format.BlueMask) >> format.BlueShift)); + } +} + + +/// +/// Adds two channel values, holding the result at 255 rather than letting it wrap. +/// +/// One value. +/// The other. +/// std::uint32_t; The sum, at most 255. +inline std::uint32_t Add_Saturated(std::uint32_t left, std::uint32_t right) +{ + std::uint32_t const sum = (left & 0xFF) + (right & 0xFF); + return((sum > 255) ? 255 : sum); +} + + +/* + * How the table-driven brightening puts a pixel back together. The channels arrive already + * separated, so only the reassembly differs between layouts. + */ +struct BrightenFormat { + std::uint32_t Down; + std::uint32_t BlueDown; + std::uint32_t GreenUp; + std::uint32_t RedUp; + std::uint32_t 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. + */ +std::uint32_t const ALTERNATE_MARKER = 0x423A0A60; + +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 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) +{ + std::uint8_t const * mulrow = mulbuffer; + std::uint8_t * colorrow = (std::uint8_t *)colorbuffer; + + for (std::int32_t y = 0; y < height; y++) { + std::uint8_t const * mul = mulrow; + std::uint16_t * color = (std::uint16_t *)colorrow; + + for (std::int32_t x = 0; x < width; x++) { + std::uint32_t const multiplier = *mul; + + if (multiplier != 0) { + 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. + */ + std::uint32_t const blue = entry & 0xFF; + std::uint32_t const green = (entry >> 8) & 0xFF; + std::uint32_t const red = (entry >> 16) & 0xFF; + + 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; + + 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 == ALTERNATE_MARKER) { + result |= (greenpart & ALTERNATE_MARKER); + result |= redpart; + } else { + result |= greenpart; + result |= (redpart & (format.Mask * 256)); + } + + *color = (std::uint16_t)result; + } + + mul++; + color++; + } + + mulrow += mulbuffwidth; + colorrow += colorbuffwidth; + } +} + +} // namespace + + +extern "C" { + +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((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, std::int32_t red, std::int32_t green, std::int32_t blue, std::int32_t intensity, void * mask) +{ + 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, std::int32_t red, std::int32_t green, std::int32_t blue, std::int32_t intensity, void * mask) +{ + 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, std::int32_t red, std::int32_t green, std::int32_t blue, std::int32_t intensity, void * mask) +{ + Adjust_Color((std::uint8_t const *)palette, (std::uint16_t *)translator, red, green, blue, intensity, (std::uint8_t const *)mask, _Format655); +} + + +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) +{ + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, colortable, _Brighten565); +} + + +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) +{ + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, colortable, _Brighten555); +} + + +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) +{ + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, colortable, _Brighten556); +} + + +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) +{ + Brighten_Color(mulbuffer, colorbuffer, mulbuffwidth, colorbuffwidth, width, height, colortable, _Brighten655); +} + +} // extern "C" 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/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/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/ovrlight.cpp b/code/ovrlight.cpp index 13e2b8e8..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,29 +28,23 @@ 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" { /* - * 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); -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); } @@ -113,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. @@ -160,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()); } } } @@ -177,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]; @@ -240,39 +230,23 @@ void SpotLightClass::Draw_It(void) unsigned char *sptr_row = sptr; unsigned short *dptr_row = dptr; - if (SpotLightDontUseMMX != 1) { + if (SpotLightColorTable != 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); - } + Brighten_Color_555(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightColorTable); 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); - } + Brighten_Color_556(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightColorTable); 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); - } + Brighten_Color_565(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightColorTable); 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); - } + Brighten_Color_655(sptr, dptr, 256, stride, srect.Width, srect.Height, SpotLightColorTable); break; default: 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/code/voxlib.cpp b/code/voxlib.cpp index 21df08d8..02e5a37a 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: a layer + * without normals has nothing to light, so lighting does not change which drawer is wanted. + */ +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,9 @@ void __cdecl Draw_Voxel_Regular(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr++; - /// 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; pixel_x += state->TransformMatrix[3].I; pixel_y += state->TransformMatrix[3].J; @@ -2067,10 +2044,9 @@ void __cdecl Draw_Voxel_Reverse(VoxelFuncArgumentStruct * state) unsigned char color_index = *ptr; ptr--; - /// 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; pixel_x += state->TransformMatrix[3].I; pixel_y += state->TransformMatrix[3].J; 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 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/CMakeLists.txt b/tests/CMakeLists.txt index 785dd4b5..003214f4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,3 +6,5 @@ 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..3e4d8a34 --- /dev/null +++ b/tests/colorops/colorgolden.h @@ -0,0 +1,93 @@ +/******************************************************************************* + * 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 Width; + int Height; + unsigned int Seed; + unsigned long long Hash; +}; + +static BrightenGoldenCase const BrightenGoldenCases[] = { + {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 = 32; diff --git a/tests/colorops/coloropstest.cpp b/tests/colorops/coloropstest.cpp new file mode 100644 index 00000000..dbba0e08 --- /dev/null +++ b/tests/colorops/coloropstest.cpp @@ -0,0 +1,162 @@ +/******************************************************************************* + * 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, 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 { + +unsigned char Palette[256 * 3]; +unsigned char Mask[256]; +unsigned short Translator[256]; + +unsigned char MulBuffer[256 * 256]; +unsigned short ColorBuffer[512 * 512]; +int ColorTable[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, 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}; + +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++) { + ColorTable[j] = (int)(Next_Random() & 0x00FFFFFF); + } + + 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 Brighten_Color_%s %dx%d: expected %llu, got %llu\n", + 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/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. 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..02b4b73e --- /dev/null +++ b/tests/voxeldraw/voxeldraw.cpp @@ -0,0 +1,241 @@ +/******************************************************************************* + * 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); + } + } + + /* + * 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); + } +} + + +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..41a1e1b5 --- /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, 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}, + {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;