mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-10 14:51:40 +00:00
- restore the old main from zdbsp
This commit is contained in:
parent
484737bb66
commit
dcf8fbae0a
2 changed files with 512 additions and 44 deletions
|
@ -283,6 +283,10 @@ static void Surface_AllocateFromLeaf(FLevel &doomMap)
|
|||
|
||||
void Surface_AllocateFromMap(FLevel &doomMap)
|
||||
{
|
||||
for (unsigned int i = 0; i < surfaces.Length(); i++)
|
||||
Mem_Free(surfaces[i]);
|
||||
surfaces = {};
|
||||
|
||||
doomMap.segSurfaces[0] = (surface_t**)Mem_Calloc(sizeof(surface_t*) * doomMap.NumGLSegs, hb_static);
|
||||
doomMap.segSurfaces[1] = (surface_t**)Mem_Calloc(sizeof(surface_t*) * doomMap.NumGLSegs, hb_static);
|
||||
doomMap.segSurfaces[2] = (surface_t**)Mem_Calloc(sizeof(surface_t*) * doomMap.NumGLSegs, hb_static);
|
||||
|
|
552
src/main.cpp
552
src/main.cpp
|
@ -1,43 +1,120 @@
|
|||
/*
|
||||
The main glue for ZDRay.
|
||||
Copyright (C) 2002-2006 Randy Heit
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Need windows.h for QueryPerformanceCounter
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#define HAVE_TIMING 1
|
||||
#define START_COUNTER(s,e,f) \
|
||||
LARGE_INTEGER s, e, f; QueryPerformanceCounter (&s);
|
||||
#define END_COUNTER(s,e,f,l) \
|
||||
QueryPerformanceCounter (&e); QueryPerformanceFrequency (&f); \
|
||||
if (!NoTiming) printf (l, double(e.QuadPart - s.QuadPart) / double(f.QuadPart));
|
||||
|
||||
#else
|
||||
|
||||
#include <time.h>
|
||||
#define HAVE_TIMING 1
|
||||
#define START_COUNTER(s,e,f) \
|
||||
clock_t s, e; s = clock();
|
||||
#define END_COUNTER(s,e,f,l) \
|
||||
e = clock(); \
|
||||
if (!NoTiming) printf (l, double(e - s) / CLOCKS_PER_SEC);
|
||||
|
||||
// Need these to check if input/output are the same file
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "commandline/getopt.h"
|
||||
|
||||
#include "framework/zdray.h"
|
||||
#include "wad/wad.h"
|
||||
#include "level/level.h"
|
||||
#include "commandline/getopt.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
static void ParseArgs(int argc, char **argv);
|
||||
static void ShowUsage();
|
||||
static void ShowVersion();
|
||||
static bool CheckInOutNames();
|
||||
|
||||
const char *Map = nullptr;
|
||||
const char *InName = nullptr;
|
||||
const char *OutName = "zdray.bin";
|
||||
bool ShowMap = false;
|
||||
bool ShowWarnings = false;
|
||||
#ifndef DISABLE_SSE
|
||||
static void CheckSSE();
|
||||
#endif
|
||||
|
||||
bool BuildGLNodes = true;
|
||||
bool ConformNodes = false;
|
||||
bool GLOnly = true;
|
||||
bool CompressNodes = true;
|
||||
bool CompressGLNodes = true;
|
||||
bool ForceCompression = true;
|
||||
bool V5GLNodes = true;
|
||||
bool HaveSSE1 = true;
|
||||
bool HaveSSE2 = true;
|
||||
int SSELevel = 2;
|
||||
bool WriteComments = true;
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
// Constants that used to be args in zdbsp
|
||||
bool NoPrune = false;
|
||||
EBlockmapMode BlockmapMode = EBM_Rebuild;
|
||||
ERejectMode RejectMode = ERM_DontTouch;
|
||||
int MaxSegs = 64;
|
||||
int SplitCost = 8;
|
||||
int AAPreference = 16;
|
||||
bool CheckPolyobjs = true;
|
||||
extern "C" int optind;
|
||||
extern "C" char *optarg;
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
const char *Map = NULL;
|
||||
const char *InName;
|
||||
const char *OutName = "tmp.wad";
|
||||
bool BuildNodes = true;
|
||||
bool BuildGLNodes = true;// false;
|
||||
bool ConformNodes = false;
|
||||
bool NoPrune = false;
|
||||
EBlockmapMode BlockmapMode = EBM_Rebuild;
|
||||
ERejectMode RejectMode = ERM_DontTouch;
|
||||
bool WriteComments = false;
|
||||
int MaxSegs = 64;
|
||||
int SplitCost = 8;
|
||||
int AAPreference = 16;
|
||||
bool CheckPolyobjs = true;
|
||||
bool ShowMap = false;
|
||||
bool ShowWarnings = false;
|
||||
bool NoTiming = false;
|
||||
bool CompressNodes = false;
|
||||
bool CompressGLNodes = false;
|
||||
bool ForceCompression = false;
|
||||
bool GLOnly = true;// false;
|
||||
bool V5GLNodes = true;// false;
|
||||
bool HaveSSE1, HaveSSE2;
|
||||
int SSELevel;
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static option long_opts[] =
|
||||
{
|
||||
|
@ -49,19 +126,51 @@ static option long_opts[] =
|
|||
{"output", required_argument, 0, 'o'},
|
||||
{"output-file", required_argument, 0, 'o'},
|
||||
{"file", required_argument, 0, 'f'},
|
||||
{"no-nodes", no_argument, 0, 'N'},
|
||||
{"gl", no_argument, 0, 'g'},
|
||||
{"gl-matching", no_argument, 0, 'G'},
|
||||
{"empty-blockmap", no_argument, 0, 'b'},
|
||||
{"empty-reject", no_argument, 0, 'r'},
|
||||
{"zero-reject", no_argument, 0, 'R'},
|
||||
{"full-reject", no_argument, 0, 'e'},
|
||||
{"no-reject", no_argument, 0, 'E'},
|
||||
{"partition", required_argument, 0, 'p'},
|
||||
{"split-cost", required_argument, 0, 's'},
|
||||
{"diagonal-cost", required_argument, 0, 'd'},
|
||||
{"no-polyobjs", no_argument, 0, 'P'},
|
||||
{"no-prune", no_argument, 0, 'q'},
|
||||
{"no-timing", no_argument, 0, 't'},
|
||||
{"compress", no_argument, 0, 'z'},
|
||||
{"compress-normal", no_argument, 0, 'Z'},
|
||||
{"extended", no_argument, 0, 'X'},
|
||||
{"gl-only", no_argument, 0, 'x'},
|
||||
{"gl-v5", no_argument, 0, '5'},
|
||||
{"no-sse", no_argument, 0, 1002},
|
||||
{"no-sse2", no_argument, 0, 1003},
|
||||
{"comments", no_argument, 0, 'c'},
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
static const char short_opts[] = "wVvm:o:f:";
|
||||
static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZXx5c";
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool fixSame = false;
|
||||
|
||||
#ifdef DISABLE_SSE
|
||||
HaveSSE1 = HaveSSE2 = false;
|
||||
#else
|
||||
HaveSSE1 = HaveSSE2 = true;
|
||||
#endif
|
||||
|
||||
ParseArgs(argc, argv);
|
||||
|
||||
if (InName == nullptr)
|
||||
if (InName == NULL)
|
||||
{
|
||||
if (optind >= argc || optind < argc - 1)
|
||||
{
|
||||
{ // Source file is unspecified or followed by junk
|
||||
ShowUsage();
|
||||
return 0;
|
||||
}
|
||||
|
@ -69,27 +178,102 @@ int main(int argc, char **argv)
|
|||
InName = argv[optind];
|
||||
}
|
||||
|
||||
#ifndef DISABLE_SSE
|
||||
CheckSSE();
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
FWadReader inwad(InName);
|
||||
START_COUNTER(t1a, t1b, t1c)
|
||||
|
||||
int lump = 0;
|
||||
int max = inwad.NumLumps();
|
||||
while (lump < max)
|
||||
if (CheckInOutNames())
|
||||
{
|
||||
if (inwad.IsMap(lump) && (!Map || stricmp(inwad.LumpName(lump), Map) == 0))
|
||||
{
|
||||
FProcessor processor(inwad, lump);
|
||||
processor.BuildNodes();
|
||||
processor.BuildLightmaps("lightconfig.txt");
|
||||
// When the input and output files are the same, output will go to
|
||||
// a temporary file. After everything is done, the input file is
|
||||
// deleted and the output file is renamed to match the input file.
|
||||
|
||||
lump = inwad.LumpAfterMap(lump);
|
||||
char *out = new char[strlen(OutName) + 3], *dot;
|
||||
|
||||
if (out == NULL)
|
||||
{
|
||||
throw std::runtime_error("Could not create temporary file name.");
|
||||
}
|
||||
|
||||
strcpy(out, OutName);
|
||||
dot = strrchr(out, '.');
|
||||
if (dot && (dot[1] == 'w' || dot[1] == 'W')
|
||||
&& (dot[2] == 'a' || dot[2] == 'A')
|
||||
&& (dot[3] == 'd' || dot[3] == 'D')
|
||||
&& dot[4] == 0)
|
||||
{
|
||||
// *.wad becomes *.daw
|
||||
dot[1] = 'd';
|
||||
dot[3] = 'w';
|
||||
}
|
||||
else
|
||||
{
|
||||
++lump;
|
||||
// * becomes *.x
|
||||
strcat(out, ".x");
|
||||
}
|
||||
OutName = out;
|
||||
fixSame = true;
|
||||
}
|
||||
|
||||
{
|
||||
FWadReader inwad(InName);
|
||||
FWadWriter outwad(OutName, inwad.IsIWAD());
|
||||
|
||||
int lump = 0;
|
||||
int max = inwad.NumLumps();
|
||||
|
||||
while (lump < max)
|
||||
{
|
||||
if (inwad.IsMap(lump) && (!Map || stricmp(inwad.LumpName(lump), Map) == 0))
|
||||
{
|
||||
START_COUNTER(t2a, t2b, t2c)
|
||||
FProcessor builder(inwad, lump);
|
||||
builder.BuildNodes();
|
||||
builder.BuildLightmaps("lightconfig.txt");
|
||||
builder.Write(outwad);
|
||||
END_COUNTER(t2a, t2b, t2c, " %.3f seconds.\n")
|
||||
|
||||
lump = inwad.LumpAfterMap(lump);
|
||||
}
|
||||
else if (inwad.IsGLNodes(lump))
|
||||
{
|
||||
// Ignore GL nodes from the input for any maps we process.
|
||||
if (BuildNodes && (Map == NULL || stricmp(inwad.LumpName(lump) + 3, Map) == 0))
|
||||
{
|
||||
lump = inwad.SkipGLNodes(lump);
|
||||
}
|
||||
else
|
||||
{
|
||||
outwad.CopyLump(inwad, lump);
|
||||
++lump;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf ("copy %s\n", inwad.LumpName (lump));
|
||||
outwad.CopyLump(inwad, lump);
|
||||
++lump;
|
||||
}
|
||||
}
|
||||
|
||||
outwad.Close();
|
||||
}
|
||||
|
||||
if (fixSame)
|
||||
{
|
||||
remove(InName);
|
||||
if (0 != rename(OutName, InName))
|
||||
{
|
||||
printf("The output file could not be renamed to %s.\nYou can find it as %s.\n",
|
||||
InName, OutName);
|
||||
}
|
||||
}
|
||||
|
||||
END_COUNTER(t1a, t1b, t1c, "\nTotal time: %.3f seconds.\n")
|
||||
}
|
||||
catch (std::runtime_error msg)
|
||||
{
|
||||
|
@ -117,11 +301,17 @@ int main(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ParseArgs
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void ParseArgs(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt_long(argc, argv, short_opts, long_opts, nullptr)) != EOF)
|
||||
while ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != EOF)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
|
@ -143,10 +333,99 @@ static void ParseArgs(int argc, char **argv)
|
|||
case 'f':
|
||||
InName = optarg;
|
||||
break;
|
||||
case 'N':
|
||||
BuildNodes = false;
|
||||
break;
|
||||
case 'b':
|
||||
BlockmapMode = EBM_Create0;
|
||||
break;
|
||||
case 'r':
|
||||
RejectMode = ERM_Create0;
|
||||
break;
|
||||
case 'R':
|
||||
RejectMode = ERM_CreateZeroes;
|
||||
break;
|
||||
case 'e':
|
||||
RejectMode = ERM_Rebuild;
|
||||
break;
|
||||
case 'E':
|
||||
RejectMode = ERM_DontTouch;
|
||||
break;
|
||||
case 'p':
|
||||
MaxSegs = atoi(optarg);
|
||||
if (MaxSegs < 3)
|
||||
{ // Don't be too unreasonable
|
||||
MaxSegs = 3;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
SplitCost = atoi(optarg);
|
||||
if (SplitCost < 1)
|
||||
{ // 1 means to add no extra weight at all
|
||||
SplitCost = 1;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
AAPreference = atoi(optarg);
|
||||
if (AAPreference < 1)
|
||||
{
|
||||
AAPreference = 1;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
CheckPolyobjs = false;
|
||||
break;
|
||||
case 'g':
|
||||
BuildGLNodes = true;
|
||||
ConformNodes = false;
|
||||
break;
|
||||
case 'G':
|
||||
BuildGLNodes = true;
|
||||
ConformNodes = true;
|
||||
break;
|
||||
case 'X':
|
||||
CompressNodes = true;
|
||||
CompressGLNodes = true;
|
||||
ForceCompression = false;
|
||||
break;
|
||||
case 'z':
|
||||
CompressNodes = true;
|
||||
CompressGLNodes = true;
|
||||
ForceCompression = true;
|
||||
break;
|
||||
case 'Z':
|
||||
CompressNodes = true;
|
||||
CompressGLNodes = false;
|
||||
ForceCompression = true;
|
||||
break;
|
||||
case 'x':
|
||||
GLOnly = true;
|
||||
BuildGLNodes = true;
|
||||
ConformNodes = false;
|
||||
break;
|
||||
case '5':
|
||||
V5GLNodes = true;
|
||||
break;
|
||||
case 'q':
|
||||
NoPrune = true;
|
||||
break;
|
||||
case 't':
|
||||
NoTiming = true;
|
||||
break;
|
||||
case 'c':
|
||||
WriteComments = true;
|
||||
break;
|
||||
case 'V':
|
||||
ShowVersion();
|
||||
exit(0);
|
||||
break;
|
||||
case 1002: // Disable SSE/SSE2 ClassifyLine routine
|
||||
HaveSSE1 = false;
|
||||
HaveSSE2 = false;
|
||||
break;
|
||||
case 1003: // Disable only SSE2 ClassifyLine routine
|
||||
HaveSSE2 = false;
|
||||
break;
|
||||
case 1000:
|
||||
ShowUsage();
|
||||
exit(0);
|
||||
|
@ -168,18 +447,40 @@ static void ShowUsage()
|
|||
printf(
|
||||
"Usage: zdray [options] sourcefile.wad\n"
|
||||
" -m, --map=MAP Only affect the specified map\n"
|
||||
" -o, --output=FILE Write output to FILE instead of zdray.bin\n"
|
||||
" -o, --output=FILE Write output to FILE instead of tmp.wad\n"
|
||||
" -q, --no-prune Keep unused sidedefs and sectors\n"
|
||||
" -N, --no-nodes Do not rebuild nodes\n"
|
||||
" -g, --gl Build GL-friendly nodes\n"
|
||||
" -G, --gl-matching Build GL-friendly nodes that match normal nodes\n"
|
||||
" -x, --gl-only Only build GL-friendly nodes\n"
|
||||
" -5, --gl-v5 Create v5 GL-friendly nodes (overriden by -z and -X)\n"
|
||||
" -X, --extended Create extended nodes (including GL nodes, if built)\n"
|
||||
" -z, --compress Compress the nodes (including GL nodes, if built)\n"
|
||||
" -Z, --compress-normal Compress normal nodes but not GL nodes\n"
|
||||
" -b, --empty-blockmap Create an empty blockmap\n"
|
||||
" -r, --empty-reject Create an empty reject table\n"
|
||||
" -R, --zero-reject Create a reject table of all zeroes\n"
|
||||
//" -e, --full-reject Rebuild reject table (unsupported)\n"
|
||||
" -E, --no-reject Leave reject table untouched\n"
|
||||
" -p, --partition=NNN Maximum segs to consider at each node (default %d)\n"
|
||||
" -s, --split-cost=NNN Cost for splitting segs (default %d)\n"
|
||||
" -d, --diagonal-cost=NNN Cost for avoiding diagonal splitters (default %d)\n"
|
||||
" -P, --no-polyobjs Do not check for polyobject subsector splits\n"
|
||||
#ifdef _WIN32
|
||||
" -v, --view View progress\n"
|
||||
" -v, --view View the nodes\n"
|
||||
#endif
|
||||
" -w, --warn Show warning messages\n"
|
||||
#if HAVE_TIMING
|
||||
" -t, --no-timing Suppress timing information\n"
|
||||
#endif
|
||||
" -V, --version Display version information\n"
|
||||
" --help Display this usage information"
|
||||
#ifndef _WIN32
|
||||
"\n"
|
||||
#else
|
||||
"\r\n"
|
||||
#endif
|
||||
, MaxSegs /* Partition size */
|
||||
, SplitCost
|
||||
, AAPreference
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -220,6 +521,169 @@ static void ShowVersion()
|
|||
" : " __DATE__ ")\n");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CheckInOutNames
|
||||
//
|
||||
// Returns true if InName and OutName refer to the same file. This needs
|
||||
// to be implemented different under Windows than Unix because the inode
|
||||
// information returned by stat is always 0, so it cannot be used to
|
||||
// determine duplicate files.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool CheckInOutNames()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct stat info;
|
||||
dev_t outdev;
|
||||
ino_t outinode;
|
||||
|
||||
if (0 != stat(OutName, &info))
|
||||
{ // If out doesn't exist, it can't be duplicated
|
||||
return false;
|
||||
}
|
||||
outdev = info.st_dev;
|
||||
outinode = info.st_ino;
|
||||
if (0 != stat(InName, &info))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return outinode == info.st_ino && outdev == info.st_dev;
|
||||
#else
|
||||
HANDLE inFile, outFile;
|
||||
|
||||
outFile = CreateFile(OutName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (outFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
inFile = CreateFile(InName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (inFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(outFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION inInfo, outInfo;
|
||||
bool same = false;
|
||||
|
||||
if (GetFileInformationByHandle(inFile, &inInfo) &&
|
||||
GetFileInformationByHandle(outFile, &outInfo))
|
||||
{
|
||||
same = inInfo.dwVolumeSerialNumber == outInfo.dwVolumeSerialNumber &&
|
||||
inInfo.nFileIndexLow == outInfo.nFileIndexLow &&
|
||||
inInfo.nFileIndexHigh == outInfo.nFileIndexHigh;
|
||||
}
|
||||
|
||||
CloseHandle(inFile);
|
||||
CloseHandle(outFile);
|
||||
|
||||
return same;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CheckSSE
|
||||
//
|
||||
// Checks if the processor supports SSE or SSE2.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
#ifndef DISABLE_SSE
|
||||
static void CheckSSE()
|
||||
{
|
||||
#ifdef __SSE2__
|
||||
// If we compiled with SSE2 support enabled for everything, then
|
||||
// obviously it's available, or the program won't get very far.
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!HaveSSE2 && !HaveSSE1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool forcenosse1 = !HaveSSE1;
|
||||
bool forcenosse2 = !HaveSSE2;
|
||||
|
||||
HaveSSE1 = false;
|
||||
HaveSSE2 = false;
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
#ifdef _M_X64
|
||||
// Processors implementing AMD64 are required to support SSE2.
|
||||
return;
|
||||
#else
|
||||
__asm
|
||||
{
|
||||
pushfd // save EFLAGS
|
||||
pop eax // store EFLAGS in EAX
|
||||
mov edx, eax // save in EDX for later testing
|
||||
xor eax, 0x00200000 // toggle bit 21
|
||||
push eax // put to stack
|
||||
popfd // save changed EAX to EFLAGS
|
||||
pushfd // push EFLAGS to TOS
|
||||
pop eax // store EFLAGS in EAX
|
||||
cmp eax, edx // see if bit 21 has changed
|
||||
jz noid // if no change, then no CPUID
|
||||
|
||||
// Check the feature flag for SSE/SSE2
|
||||
mov eax, 1
|
||||
cpuid
|
||||
test edx, (1 << 25) // Check for SSE
|
||||
setnz HaveSSE1
|
||||
test edx, (1 << 26) // Check for SSE2
|
||||
setnz HaveSSE2
|
||||
noid :
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
|
||||
// Same as above, but for GCC
|
||||
asm volatile
|
||||
("pushfl\n\t"
|
||||
"popl %%eax\n\t"
|
||||
"movl %%eax,%%edx\n\t"
|
||||
"xorl $0x200000,%%eax\n\t"
|
||||
"pushl %%eax\n\t"
|
||||
"popfl\n\t"
|
||||
"pushfl\n\t"
|
||||
"popl %%eax\n\t"
|
||||
"cmp %%edx,%%eax\n\t"
|
||||
"jz noid\n\t"
|
||||
"mov $1,%%eax\n\t"
|
||||
"cpuid\n\t"
|
||||
"test $(1<<25),%%edx\n\t"
|
||||
"setneb %0\n"
|
||||
"test $(1<<26),%%edx\n\t"
|
||||
"setneb %1\n"
|
||||
"noid:"
|
||||
:"=m" (HaveSSE1), "=m" (HaveSSE2)::"eax", "ebx", "ecx", "edx");
|
||||
|
||||
#endif
|
||||
|
||||
if (forcenosse1)
|
||||
{
|
||||
HaveSSE1 = false;
|
||||
}
|
||||
if (forcenosse2)
|
||||
{
|
||||
HaveSSE2 = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Warn
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void Warn(const char *format, ...)
|
||||
{
|
||||
va_list marker;
|
||||
|
|
Loading…
Reference in a new issue