mirror of
https://github.com/mangosfour/server.git
synced 2026-01-01 07:37:07 +00:00
[12632] Revert previous commit (see Notes)
This commit is contained in:
parent
1cd806c02e
commit
ef445ea523
1462 changed files with 9689 additions and 7080 deletions
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
|
||||
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
||||
#
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file AABox.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
@ -282,6 +282,10 @@ bool AABox::culledBy(
|
|||
return false;
|
||||
}
|
||||
|
||||
void AABox::getBounds(Sphere& s) const {
|
||||
s.center = center();
|
||||
s.radius = extent().length() / 2;
|
||||
}
|
||||
|
||||
bool AABox::intersects(const class Sphere& sphere) const {
|
||||
double d = 0;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
/**
|
||||
/*
|
||||
@file Any.cpp
|
||||
|
||||
@author Morgan McGuire
|
||||
@author Shawn Yarbrough
|
||||
|
||||
@created 2006-06-11
|
||||
@edited 2009-11-15
|
||||
@edited 2010-07-24
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
|
|
@ -15,11 +15,73 @@
|
|||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
|
||||
namespace G3D {
|
||||
|
||||
std::string Any::resolveStringAsFilename() const {
|
||||
verifyType(STRING);
|
||||
std::string f = FileSystem::resolve(string(), sourceDirectory());
|
||||
if (FileSystem::exists(f)) {
|
||||
return f;
|
||||
} else {
|
||||
const std::string& s = System::findDataFile(string(), false);
|
||||
if (s.empty()) {
|
||||
return string();
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Any::nameBeginsWith(const std::string& s) const {
|
||||
return nameBeginsWith(s.c_str());
|
||||
}
|
||||
|
||||
|
||||
bool Any::nameEquals(const std::string& s) const {
|
||||
// If std::string has a fast hash compare, use it first
|
||||
return (name() == s) || nameEquals(s.c_str());
|
||||
}
|
||||
|
||||
|
||||
inline static char toLower(char c) {
|
||||
return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c;
|
||||
}
|
||||
|
||||
|
||||
bool Any::nameBeginsWith(const char* s) const {
|
||||
verifyType(Any::ARRAY, Any::TABLE);
|
||||
|
||||
const char* n = name().c_str();
|
||||
// Walk through character-by-character
|
||||
while ((*s != '\0') && (*n != '\0')) {
|
||||
if (toLower(*s) != toLower(*n)) {
|
||||
// Mismatch
|
||||
return false;
|
||||
}
|
||||
++s; ++n;
|
||||
}
|
||||
// Make sure s ran out no later than n
|
||||
return (*s == '\0');
|
||||
}
|
||||
|
||||
|
||||
bool Any::nameEquals(const char* s) const {
|
||||
verifyType(Any::ARRAY, Any::TABLE);
|
||||
#ifdef G3D_WIN32
|
||||
return stricmp(name().c_str(), s) == 0;
|
||||
#else
|
||||
return strcasecmp(name().c_str(), s) == 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Any::beforeRead() const {
|
||||
if (isPlaceholder()) {
|
||||
// Tried to read from a placeholder--throw an exception as if
|
||||
|
|
@ -675,11 +737,10 @@ bool Any::operator!=(const Any& x) const {
|
|||
static void getDeserializeSettings(TextInput::Settings& settings) {
|
||||
settings.cppBlockComments = true;
|
||||
settings.cppLineComments = true;
|
||||
settings.otherLineComments = true;
|
||||
settings.otherCommentCharacter = '#';
|
||||
settings.otherLineComments = false;
|
||||
settings.generateCommentTokens = true;
|
||||
settings.singleQuotedStrings = false;
|
||||
settings.msvcSpecials = false;
|
||||
settings.msvcFloatSpecials = false;
|
||||
settings.caseSensitive = false;
|
||||
}
|
||||
|
||||
|
|
@ -708,7 +769,7 @@ void Any::load(const std::string& filename) {
|
|||
TextInput::Settings settings;
|
||||
getDeserializeSettings(settings);
|
||||
|
||||
TextInput ti(filename, settings);
|
||||
TextInput ti(FileSystem::resolve(filename), settings);
|
||||
deserialize(ti);
|
||||
}
|
||||
|
||||
|
|
@ -870,12 +931,6 @@ static bool isClose(const char c) {
|
|||
}
|
||||
|
||||
|
||||
/** True if \a s is a C++ name operator */
|
||||
static bool isNameOperator(const std::string& s) {
|
||||
return s == "." || s == "::" || s == "->";
|
||||
}
|
||||
|
||||
|
||||
void Any::deserializeName(TextInput& ti, Token& token, std::string& name) {
|
||||
debugAssert(token.type() == Token::SYMBOL);
|
||||
std::string s = token.string();
|
||||
|
|
@ -928,6 +983,9 @@ void Any::deserialize(TextInput& ti, Token& token) {
|
|||
"File ended without a properly formed Any");
|
||||
}
|
||||
|
||||
// Do we need to read one more token after the end?
|
||||
bool needRead = true;
|
||||
|
||||
switch (token.type()) {
|
||||
case Token::STRING:
|
||||
m_type = STRING;
|
||||
|
|
@ -951,8 +1009,41 @@ void Any::deserialize(TextInput& ti, Token& token) {
|
|||
break;
|
||||
|
||||
case Token::SYMBOL:
|
||||
// Named Array, Named Table, Array, Table, or NONE
|
||||
if (toUpper(token.string()) == "NONE") {
|
||||
// Pragma, Named Array, Named Table, Array, Table, or NONE
|
||||
if (token.string() == "#") {
|
||||
// Pragma
|
||||
|
||||
// Currently, "include" is the only pragma allowed
|
||||
token = ti.read();
|
||||
if (! ((token.type() == Token::SYMBOL) &&
|
||||
(token.string() == "include"))) {
|
||||
throw ParseError(ti.filename(), token.line(), token.character(),
|
||||
"Expected 'include' pragma after '#'");
|
||||
}
|
||||
|
||||
ti.readSymbol("(");
|
||||
const std::string& includeName = ti.readString();
|
||||
|
||||
// Find the include file
|
||||
const std::string& myPath = filenamePath(ti.filename());
|
||||
std::string t = pathConcat(myPath, includeName);
|
||||
|
||||
if (! FileSystem::exists(t)) {
|
||||
// Try and find it, starting with cwd
|
||||
t = System::findDataFile(includeName);
|
||||
}
|
||||
|
||||
// Read the included file
|
||||
load(t);
|
||||
|
||||
// Update the source information
|
||||
ensureData();
|
||||
m_data->source.filename +=
|
||||
format(" [included from %s:%d(%d)]", ti.filename().c_str(), token.line(), token.character());
|
||||
|
||||
ti.readSymbol(")");
|
||||
|
||||
} else if (toUpper(token.string()) == "NONE") {
|
||||
// Nothing left to do; we initialized to NONE originally
|
||||
ensureData();
|
||||
m_data->source.set(ti, token);
|
||||
|
|
@ -982,6 +1073,7 @@ void Any::deserialize(TextInput& ti, Token& token) {
|
|||
ensureData();
|
||||
m_data->name = name;
|
||||
}
|
||||
needRead = false;
|
||||
} // if NONE
|
||||
break;
|
||||
|
||||
|
|
@ -996,7 +1088,7 @@ void Any::deserialize(TextInput& ti, Token& token) {
|
|||
m_data->comment = comment;
|
||||
}
|
||||
|
||||
if (m_type != ARRAY && m_type != TABLE) {
|
||||
if (needRead) {
|
||||
// Array and table already consumed their last token
|
||||
token = ti.read();
|
||||
}
|
||||
|
|
@ -1016,9 +1108,9 @@ static bool isSeparator(char c) {
|
|||
|
||||
|
||||
void Any::readUntilCommaOrClose(TextInput& ti, Token& token) {
|
||||
while (! ((token.type() == Token::SYMBOL) &&
|
||||
(isClose(token.string()[0])) ||
|
||||
isSeparator(token.string()[0]))) {
|
||||
bool atClose = (token.type() == Token::SYMBOL) && isClose(token.string()[0]);
|
||||
bool atComma = isSeparator(token.string()[0]);
|
||||
while (! (atClose || atComma)) {
|
||||
switch (token.type()) {
|
||||
case Token::NEWLINE:
|
||||
case Token::COMMENT:
|
||||
|
|
@ -1030,6 +1122,10 @@ void Any::readUntilCommaOrClose(TextInput& ti, Token& token) {
|
|||
throw ParseError(ti.filename(), token.line(), token.character(),
|
||||
"Expected a comma or close paren");
|
||||
}
|
||||
|
||||
// Update checks
|
||||
atComma = isSeparator(token.string()[0]);
|
||||
atClose = (token.type() == Token::SYMBOL) && isClose(token.string()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1076,13 +1172,13 @@ void Any::deserializeBody(TextInput& ti, Token& token) {
|
|||
}
|
||||
|
||||
key = token.string();
|
||||
// Consume everything up to the = sign
|
||||
// Consume everything up to the = sign, returning the "=" sign.
|
||||
token = ti.readSignificant();
|
||||
|
||||
if ((token.type() != Token::SYMBOL) || (token.string() != "=")) {
|
||||
throw ParseError(ti.filename(), token.line(), token.character(), "Expected =");
|
||||
} else {
|
||||
// Consume (don't consume comments--we want the value pointed to by a to get those).
|
||||
// Read the next token, which is the value (don't consume comments--we want the value pointed to by a to get those).
|
||||
token = ti.read();
|
||||
}
|
||||
}
|
||||
|
|
@ -1154,6 +1250,15 @@ const Any::Source& Any::source() const {
|
|||
}
|
||||
|
||||
|
||||
std::string Any::sourceDirectory() const {
|
||||
if (m_data) {
|
||||
return FilePath::parent(m_data->source.filename);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Any::verify(bool value, const std::string& message) const {
|
||||
beforeRead();
|
||||
if (! value) {
|
||||
|
|
@ -1185,6 +1290,14 @@ void Any::verifyName(const std::string& n) const {
|
|||
}
|
||||
|
||||
|
||||
void Any::verifyName(const std::string& n, const std::string& m) const {
|
||||
beforeRead();
|
||||
const std::string& x = toUpper(name());
|
||||
verify(beginsWith(x, toUpper(n)) ||
|
||||
beginsWith(x, toUpper(m)), "Name must begin with " + n + " or " + m);
|
||||
}
|
||||
|
||||
|
||||
void Any::verifyType(Type t) const {
|
||||
beforeRead();
|
||||
if (type() != t) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file AreaMemoryManager.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file BinaryFormat.cpp
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
/*
|
||||
@file BinaryInput.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
Copyright 2001-2007, Morgan McGuire. All rights reserved.
|
||||
|
||||
@created 2001-08-09
|
||||
@edited 2005-02-24
|
||||
@edited 2010-03-05
|
||||
|
||||
|
||||
<PRE>
|
||||
|
|
@ -37,8 +37,11 @@
|
|||
#include "G3D/Array.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/Log.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
#include <zlib.h>
|
||||
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
#include "zip.h"
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
#include <cstring>
|
||||
|
||||
namespace G3D {
|
||||
|
|
@ -272,28 +275,42 @@ BinaryInput::BinaryInput(
|
|||
_internal::currentFilesUsed.insert(m_filename);
|
||||
|
||||
|
||||
if (! fileExists(m_filename, false)) {
|
||||
std::string zipfile;
|
||||
std::string internalfile;
|
||||
if (zipfileExists(m_filename, zipfile, internalfile)) {
|
||||
// Load from zipfile
|
||||
void* v;
|
||||
size_t s;
|
||||
zipRead(filename, v, s);
|
||||
m_buffer = reinterpret_cast<uint8*>(v);
|
||||
m_bufferLength = m_length = s;
|
||||
if (compressed) {
|
||||
decompress();
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
std::string zipfile;
|
||||
if (FileSystem::inZipfile(m_filename, zipfile)) {
|
||||
// Load from zipfile
|
||||
// zipRead(filename, v, s);
|
||||
|
||||
std::string internalFile = m_filename.substr(zipfile.length() + 1);
|
||||
struct zip* z = zip_open(zipfile.c_str(), ZIP_CHECKCONS, NULL);
|
||||
{
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // TODO: Docs unclear if zip_stat_init is required.
|
||||
zip_stat(z, internalFile.c_str(), ZIP_FL_NOCASE, &info);
|
||||
m_bufferLength = m_length = info.size;
|
||||
// sets machines up to use MMX, if they want
|
||||
m_buffer = reinterpret_cast<uint8*>(System::alignedMalloc(m_length, 16));
|
||||
struct zip_file* zf = zip_fopen( z, internalFile.c_str(), ZIP_FL_NOCASE );
|
||||
{
|
||||
int64 test = zip_fread( zf, m_buffer, m_length );
|
||||
debugAssertM(test == m_length,
|
||||
internalFile + " was corrupt because it unzipped to the wrong size.");
|
||||
(void)test;
|
||||
}
|
||||
m_freeBuffer = true;
|
||||
} else {
|
||||
Log::common()->printf("Warning: File not found: %s\n", m_filename.c_str());
|
||||
zip_fclose( zf );
|
||||
}
|
||||
zip_close( z );
|
||||
|
||||
if (compressed) {
|
||||
decompress();
|
||||
}
|
||||
m_freeBuffer = true;
|
||||
return;
|
||||
}
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
|
||||
// Figure out how big the file is and verify that it exists.
|
||||
m_length = fileLength(m_filename);
|
||||
m_length = FileSystem::size(m_filename);
|
||||
|
||||
// Read the file into memory
|
||||
FILE* file = fopen(m_filename.c_str(), "rb");
|
||||
|
|
@ -460,6 +477,42 @@ std::string BinaryInput::readString() {
|
|||
return readString(n);
|
||||
}
|
||||
|
||||
static bool isNewline(char c) {
|
||||
return c == '\n' || c == '\r';
|
||||
}
|
||||
|
||||
std::string BinaryInput::readStringNewline() {
|
||||
int64 n = 0;
|
||||
|
||||
if ((m_pos + m_alreadyRead + n) < (m_length - 1)) {
|
||||
prepareToRead(1);
|
||||
}
|
||||
|
||||
if ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
|
||||
! isNewline(m_buffer[m_pos + n])) {
|
||||
|
||||
++n;
|
||||
while ( ((m_pos + m_alreadyRead + n) < (m_length - 1)) &&
|
||||
! isNewline(m_buffer[m_pos + n])) {
|
||||
|
||||
prepareToRead(1);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string s = readString(n);
|
||||
|
||||
// Consume the newline
|
||||
char firstNLChar = readUInt8();
|
||||
|
||||
// Consume the 2nd newline
|
||||
if (isNewline(m_buffer[m_pos + 1]) && (m_buffer[m_pos + 1] != firstNLChar)) {
|
||||
readUInt8();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
std::string BinaryInput::readStringEven() {
|
||||
std::string x = readString();
|
||||
|
|
|
|||
|
|
@ -1,22 +1,27 @@
|
|||
/**
|
||||
/*
|
||||
@file BinaryOutput.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
Copyright 2002-2007, Morgan McGuire, All rights reserved.
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
Copyright 2002-2010, Morgan McGuire, All rights reserved.
|
||||
|
||||
@created 2002-02-20
|
||||
@edited 2008-01-07
|
||||
@edited 2010-03-17
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/Array.h"
|
||||
#include <zlib.h>
|
||||
|
||||
#include "G3D/Log.h"
|
||||
#include <cstring>
|
||||
|
||||
#ifdef G3D_LINUX
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
// Largest memory buffer that the system will use for writing to
|
||||
// disk. After this (or if the system runs out of memory)
|
||||
// chunks of the file will be dumped to disk.
|
||||
|
|
@ -155,7 +160,7 @@ void BinaryOutput::reserveBytesWhenOutOfMemory(size_t bytes) {
|
|||
//debugPrintf("Writing %d bytes to disk\n", writeBytes);
|
||||
|
||||
const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
|
||||
FILE* file = fopen(m_filename.c_str(), mode);
|
||||
FILE* file = FileSystem::fopen(m_filename.c_str(), mode);
|
||||
debugAssert(file);
|
||||
|
||||
size_t count = fwrite(m_buffer, 1, writeBytes, file);
|
||||
|
|
@ -317,14 +322,17 @@ void BinaryOutput::commit(bool flush) {
|
|||
parseFilename(m_filename, root, pathArray, base, ext);
|
||||
|
||||
path = root + stringJoin(pathArray, '/');
|
||||
if (! fileExists(path, false)) {
|
||||
createDirectory(path);
|
||||
if (! FileSystem::exists(path, false)) {
|
||||
FileSystem::createDirectory(path);
|
||||
}
|
||||
|
||||
const char* mode = (m_alreadyWritten > 0) ? "ab" : "wb";
|
||||
|
||||
FILE* file = fopen(m_filename.c_str(), mode);
|
||||
FILE* file = FileSystem::fopen(m_filename.c_str(), mode);
|
||||
|
||||
if (! file) {
|
||||
logPrintf("Error %d while trying to open \"%s\"\n", errno, m_filename.c_str());
|
||||
}
|
||||
m_ok = (file != NULL) && m_ok;
|
||||
|
||||
if (m_ok) {
|
||||
|
|
@ -340,7 +348,7 @@ void BinaryOutput::commit(bool flush) {
|
|||
if (flush) {
|
||||
fflush(file);
|
||||
}
|
||||
fclose(file);
|
||||
FileSystem::fclose(file);
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Box.cpp
|
||||
Box class
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
namespace G3D {
|
||||
|
||||
/**
|
||||
/*
|
||||
Sets a field on four vertices. Used by the constructor.
|
||||
*/
|
||||
#define setMany(i0, i1, i2, i3, field, extreme) \
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Box.cpp
|
||||
Box class
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
\file BumpMapPreprocess.cpp
|
||||
|
||||
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
|
||||
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
||||
#
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Capsule.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file CollisionDetection.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Color1.cpp
|
||||
|
||||
Color class.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Color1uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Color3.cpp
|
||||
|
||||
Color class.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Color3uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Color4.cpp
|
||||
|
||||
Color class.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Color4uint8.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Cone.cpp
|
||||
|
||||
Cone class
|
||||
|
|
@ -26,7 +26,7 @@ Cone::Cone(const Vector3 &tip, const Vector3 &direction, float angle) {
|
|||
debugAssert(angle <= pi());
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
Forms the smallest cone that contains the box. Undefined if
|
||||
the tip is inside or on the box.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file ConvexPolyhedron.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file CoordinateFrame.cpp
|
||||
|
||||
Coordinate frame class
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-06-02
|
||||
@edited 2009-11-13
|
||||
@edited 2010-03-13
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
|
@ -26,23 +26,52 @@
|
|||
#include "G3D/UprightFrame.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/PhysicsFrame.h"
|
||||
#include "G3D/UprightFrame.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
||||
std::string CoordinateFrame::toXYZYPRDegreesString() const {
|
||||
UprightFrame uframe(*this);
|
||||
|
||||
return format("CFrame::fromXYZYPRDegrees(% 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff, % 5.1ff)",
|
||||
uframe.translation.x, uframe.translation.y, uframe.translation.z,
|
||||
toDegrees(uframe.yaw), toDegrees(uframe.pitch), 0.0f);
|
||||
}
|
||||
|
||||
|
||||
CoordinateFrame::CoordinateFrame(const Any& any) {
|
||||
any.verifyName("CFrame");
|
||||
if (toUpper(any.name()) == "CFRAME") {
|
||||
*this = CFrame();
|
||||
|
||||
const std::string& n = toUpper(any.name());
|
||||
|
||||
if (beginsWith(n, "VECTOR3")) {
|
||||
translation = any;
|
||||
} else if (beginsWith(n, "MATRIX3")) {
|
||||
rotation = any;
|
||||
} else if ((n == "CFRAME") || (n == "COORDINATEFRAME")) {
|
||||
any.verifyType(Any::TABLE, Any::ARRAY);
|
||||
if (any.type() == Any::TABLE) {
|
||||
rotation = any["rotation"];
|
||||
translation = any["translation"];
|
||||
} else {
|
||||
if (any.type() == Any::ARRAY) {
|
||||
any.verifySize(2);
|
||||
rotation = any[0];
|
||||
translation = any[1];
|
||||
} else {
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& n = toLower(it->key);
|
||||
if (n == "translation") {
|
||||
translation = Vector3(it->value);
|
||||
} else if (n == "rotation") {
|
||||
rotation = Matrix3(it->value);
|
||||
} else {
|
||||
any.verify(false, "Illegal table key: " + it->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (beginsWith(n, "PHYSICSFRAME") || beginsWith(n, "PFRAME")) {
|
||||
*this = PhysicsFrame(any);
|
||||
} else {
|
||||
any.verifyName("CFrame::fromXYZYPRDegrees");
|
||||
any.verifyName("CFrame::fromXYZYPRDegrees", "CoordinateFrame::fromXYZYPRDegrees");
|
||||
any.verifyType(Any::ARRAY);
|
||||
any.verifySize(3, 6);
|
||||
|
||||
|
|
@ -370,12 +399,12 @@ CoordinateFrame CoordinateFrame::lerp(
|
|||
} else if (alpha == 0.0f) {
|
||||
return *this;
|
||||
} else {
|
||||
Quat q1 = Quat(this->rotation);
|
||||
Quat q2 = Quat(other.rotation);
|
||||
const Quat q1(this->rotation);
|
||||
const Quat q2(other.rotation);
|
||||
|
||||
return CoordinateFrame(
|
||||
q1.slerp(q2, alpha).toRotationMatrix(),
|
||||
this->translation * (1 - alpha) + other.translation * alpha);
|
||||
translation * (1 - alpha) + other.translation * alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +412,7 @@ CoordinateFrame CoordinateFrame::lerp(
|
|||
void CoordinateFrame::pointToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
|
||||
vout.resize(v.size());
|
||||
|
||||
for (int i = v.size() - 1; i >= 0; --i) {
|
||||
for (int i = 0; i < v.size(); ++i) {
|
||||
vout[i] = pointToWorldSpace(v[i]);
|
||||
}
|
||||
}
|
||||
|
|
@ -392,7 +421,7 @@ void CoordinateFrame::pointToWorldSpace(const Array<Vector3>& v, Array<Vector3>&
|
|||
void CoordinateFrame::normalToWorldSpace(const Array<Vector3>& v, Array<Vector3>& vout) const {
|
||||
vout.resize(v.size());
|
||||
|
||||
for (int i = v.size() - 1; i >= 0; --i) {
|
||||
for (int i = 0; i < v.size(); ++i) {
|
||||
vout[i] = normalToWorldSpace(v[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Crypto.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Crypto_md5.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Cylinder.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
867
dep/src/g3dlite/FileSystem.cpp
Normal file
867
dep/src/g3dlite/FileSystem.cpp
Normal file
|
|
@ -0,0 +1,867 @@
|
|||
/*
|
||||
@file FileSystem.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@author 2002-06-06
|
||||
@edited 2010-04-10
|
||||
*/
|
||||
#include "G3D/FileSystem.h"
|
||||
#include "G3D/System.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
#include "zip.h"
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
#include "G3D/g3dfnmatch.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
// Needed for _getcwd
|
||||
# include <direct.h>
|
||||
|
||||
// Needed for _findfirst
|
||||
# include <io.h>
|
||||
|
||||
#define stat64 _stat64
|
||||
#else
|
||||
# include <dirent.h>
|
||||
# include <fnmatch.h>
|
||||
# include <unistd.h>
|
||||
# define _getcwd getcwd
|
||||
# define _stat stat
|
||||
#endif
|
||||
|
||||
namespace G3D {
|
||||
|
||||
static FileSystem* common = NULL;
|
||||
|
||||
FileSystem& FileSystem::instance() {
|
||||
init();
|
||||
return *common;
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::init() {
|
||||
if (common == NULL) {
|
||||
common = new FileSystem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::cleanup() {
|
||||
if (common != NULL) {
|
||||
delete common;
|
||||
common = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
FileSystem::FileSystem() : m_cacheLifetime(10) {}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
bool FileSystem::Dir::contains(const std::string& f) const {
|
||||
|
||||
for (int i = 0; i < nodeArray.size(); ++i) {
|
||||
# ifdef G3D_WIN32
|
||||
if (stricmp(f.c_str(), nodeArray[i].name.c_str()) == 0) {
|
||||
return true;
|
||||
}
|
||||
# else
|
||||
if (f == nodeArray[i].name) {
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::string& pathInsideZipfile) {
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
struct zip* z = zip_open( FilePath::removeTrailingSlash(zipfile).c_str(), ZIP_CHECKCONS, NULL );
|
||||
debugAssert(z);
|
||||
|
||||
int count = zip_get_num_files( z );
|
||||
Set<std::string> alreadyAdded;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // TODO: Docs unclear if zip_stat_init is required.
|
||||
zip_stat_index( z, i, ZIP_FL_NOCASE, &info );
|
||||
|
||||
// Fully-qualified name of a file inside zipfile
|
||||
std::string name = info.name;
|
||||
|
||||
if (beginsWith(name, pathInsideZipfile)) {
|
||||
// We found something inside the directory we were looking for,
|
||||
// so the directory itself must exist
|
||||
exists = true;
|
||||
|
||||
// For building the cached directory listing, extract only elements that do not contain
|
||||
// additional subdirectories.
|
||||
|
||||
int start = pathInsideZipfile.size();
|
||||
if ((int(name.length()) > start) && isSlash(name[start])) {
|
||||
++start;
|
||||
}
|
||||
int end = findSlash(name, start);
|
||||
if (end == -1) {
|
||||
// There are no more slashes; add this name
|
||||
name = name.substr(start);
|
||||
if (alreadyAdded.insert(name)) {
|
||||
Entry& e = nodeArray.next();
|
||||
e.name = name;
|
||||
e.type = FILE_TYPE;
|
||||
}
|
||||
} else {
|
||||
// There are more slashes, indicating that this is a directory
|
||||
name = name.substr(start, end);
|
||||
if (alreadyAdded.insert(name)) {
|
||||
Entry& e = nodeArray.next();
|
||||
e.name = name;
|
||||
e.type = DIR_TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zip_close(z);
|
||||
z = NULL;
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
}
|
||||
|
||||
|
||||
FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpdate) {
|
||||
const std::string& key =
|
||||
# if defined(G3D_WIN32)
|
||||
FilePath::canonicalize(FilePath::removeTrailingSlash(toLower(FilePath::canonicalize(resolve(path)))));
|
||||
# else
|
||||
FilePath::canonicalize(FilePath::removeTrailingSlash(FilePath::canonicalize(resolve(path))));
|
||||
# endif
|
||||
|
||||
RealTime now = System::time();
|
||||
Dir& dir = m_cache.getCreate(key);
|
||||
|
||||
if ((now > dir.lastChecked + cacheLifetime()) || forceUpdate) {
|
||||
dir = Dir();
|
||||
|
||||
// Out of date: update
|
||||
dir.lastChecked = now;
|
||||
|
||||
struct _stat st;
|
||||
const bool exists = _stat(key.c_str(), &st) != -1;
|
||||
const bool isDirectory = (st.st_mode & S_IFDIR) != 0;
|
||||
|
||||
// Does this path exist on the real filesystem?
|
||||
if (exists && isDirectory) {
|
||||
|
||||
// Is this path actually a directory?
|
||||
if (isDirectory) {
|
||||
dir.exists = true;
|
||||
// Update contents
|
||||
# ifdef G3D_WIN32
|
||||
const std::string& filespec = FilePath::concat(key, "*");
|
||||
struct _finddata_t fileinfo;
|
||||
intptr_t handle = _findfirst(filespec.c_str(), &fileinfo);
|
||||
debugAssert(handle != -1);
|
||||
int result = 0;
|
||||
do {
|
||||
if ((strcmp(fileinfo.name, ".") != 0) && (strcmp(fileinfo.name, "..") != 0)) {
|
||||
Entry& e = dir.nodeArray.next();
|
||||
e.name = fileinfo.name;
|
||||
if ((fileinfo.attrib & _A_SUBDIR) != 0) {
|
||||
e.type = DIR_TYPE;
|
||||
} else {
|
||||
e.type = FILE_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
result = _findnext(handle, &fileinfo);
|
||||
} while (result == 0);
|
||||
_findclose(handle);
|
||||
|
||||
# else
|
||||
DIR* listing = opendir(key.c_str());
|
||||
debugAssertM(listing, "opendir failed on '" + key + "'");
|
||||
struct dirent* entry = readdir(listing);
|
||||
while (entry != NULL) {
|
||||
if ((strcmp(entry->d_name, "..") != 0) && (strcmp(entry->d_name, ".") != 0)) {
|
||||
Entry& e = dir.nodeArray.next();
|
||||
e.name = entry->d_name;
|
||||
|
||||
# ifdef _DIRENT_HAVE_D_TYPE
|
||||
// Not all POSIX systems support this field
|
||||
// http://www.delorie.com/gnu/docs/glibc/libc_270.html
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR:
|
||||
e.type = DIR_TYPE;
|
||||
break;
|
||||
|
||||
case DT_REG:
|
||||
e.type = FILE_TYPE;
|
||||
break;
|
||||
|
||||
case DT_UNKNOWN:
|
||||
default:
|
||||
e.type = UNKNOWN;
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
entry = readdir(listing);
|
||||
}
|
||||
closedir(listing);
|
||||
listing = NULL;
|
||||
entry = NULL;
|
||||
# endif
|
||||
}
|
||||
|
||||
} else {
|
||||
std::string zip;
|
||||
|
||||
if (exists && isZipfile(path)) {
|
||||
// This is a zipfile; get its root
|
||||
dir.isZipfile = true;
|
||||
dir.computeZipListing(path, "");
|
||||
|
||||
} else if (inZipfile(path, zip)) {
|
||||
|
||||
// There is a zipfile somewhere in the path. Does
|
||||
// the rest of the path exist inside the zipfile?
|
||||
dir.inZipfile = true;
|
||||
|
||||
dir.computeZipListing(zip, path.substr(zip.length() + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_inZipfile(const std::string& path, std::string& z) {
|
||||
// Reject trivial cases before parsing
|
||||
if (path.find('.') == std::string::npos) {
|
||||
// There is no zipfile possible, since G3D requires
|
||||
// an extension on zipfiles.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look at all sub-paths containing periods.
|
||||
// For each, ask if it is a zipfile.
|
||||
int current = 0;
|
||||
current = path.find('.', current);
|
||||
|
||||
while (current != -1) {
|
||||
// xxxxx/foo.zip/yyyyy
|
||||
current = path.find('.', current);
|
||||
|
||||
// Look forward for the next slash
|
||||
int s = findSlash(path, current);
|
||||
|
||||
if (s == -1) {
|
||||
// No more slashes
|
||||
return false;
|
||||
}
|
||||
|
||||
z = path.substr(0, s);
|
||||
if (_isZipfile(z)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
current = s + 1;
|
||||
}
|
||||
|
||||
z = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_isZipfile(const std::string& filename) {
|
||||
if (FilePath::ext(filename).empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* f = fopen(FilePath::removeTrailingSlash(filename).c_str(), "r");
|
||||
if (f == NULL) {
|
||||
return false;
|
||||
}
|
||||
uint8 header[4];
|
||||
fread(header, 4, 1, f);
|
||||
|
||||
const uint8 zipHeader[4] = {0x50, 0x4b, 0x03, 0x04};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (header[i] != zipHeader[i]) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
FILE* FileSystem::_fopen(const char* filename, const char* mode) {
|
||||
for (const char* m = mode; *m != '\0'; ++m) {
|
||||
if (*m == 'w') {
|
||||
// Purge the cache entry for the parent of this directory
|
||||
_clearCache(FilePath::parent(_resolve(filename)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ::fopen(filename, mode);
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_clearCache(const std::string& path) {
|
||||
if ((path == "") || FilePath::isRoot(path)) {
|
||||
m_cache.clear();
|
||||
} else {
|
||||
Array<std::string> keys;
|
||||
m_cache.getKeys(keys);
|
||||
|
||||
const std::string& prefix =
|
||||
# ifdef G3D_WIN32
|
||||
toLower(FilePath::canonicalize(FilePath::removeTrailingSlash(_resolve(path))));
|
||||
# else
|
||||
FilePath::canonicalize(FilePath::removeTrailingSlash(_resolve(path)));
|
||||
# endif
|
||||
const std::string& prefixSlash = prefix + "/";
|
||||
|
||||
for (int k = 0; k < keys.size(); ++k) {
|
||||
const std::string& key = keys[k];
|
||||
if ((key == prefix) || beginsWith(key, prefixSlash)) {
|
||||
m_cache.remove(keys[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_setCacheLifetime(float t) {
|
||||
m_cacheLifetime = t;
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_createDirectory(const std::string& dir) {
|
||||
|
||||
if (dir == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string d = _resolve(dir);
|
||||
|
||||
// Add a trailing / if there isn't one.
|
||||
switch (d[d.size() - 1]) {
|
||||
case '/':
|
||||
case '\\':
|
||||
break;
|
||||
|
||||
default:
|
||||
d += "/";
|
||||
}
|
||||
|
||||
// If it already exists, do nothing
|
||||
if (_exists(FilePath::removeTrailingSlash(d))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the name apart
|
||||
std::string root, base, ext;
|
||||
Array<std::string> path;
|
||||
|
||||
std::string lead;
|
||||
FilePath::parse(d, root, path, base, ext);
|
||||
debugAssert(base == "");
|
||||
debugAssert(ext == "");
|
||||
|
||||
// Begin with an extra period so "c:\" becomes "c:\.\" after
|
||||
// appending a path and "c:" becomes "c:.\", not root: "c:\"
|
||||
std::string p = root + ".";
|
||||
|
||||
// Create any intermediate that doesn't exist
|
||||
for (int i = 0; i < path.size(); ++i) {
|
||||
p += "/" + path[i];
|
||||
if (! _exists(p)) {
|
||||
// Windows only requires one argument to mkdir,
|
||||
// where as unix also requires the permissions.
|
||||
# ifndef G3D_WIN32
|
||||
mkdir(p.c_str(), 0777);
|
||||
# else
|
||||
_mkdir(p.c_str());
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
_clearCache(FilePath::parent(FilePath::removeTrailingSlash(d)));
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_copyFile(const std::string& source, const std::string& dest) {
|
||||
# ifdef G3D_WIN32
|
||||
// TODO: handle case where srcPath is in a zipfile
|
||||
CopyFileA(source.c_str(), dest.c_str(), FALSE);
|
||||
_clearCache(FilePath::parent(_resolve(dest)));
|
||||
# else
|
||||
// Read it all in, then dump it out
|
||||
BinaryInput in(source, G3D_LITTLE_ENDIAN);
|
||||
BinaryOutput out(dest, G3D_LITTLE_ENDIAN);
|
||||
out.writeBytes(in.getCArray(), in.size());
|
||||
out.commit(false);
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_exists(const std::string& f, bool trustCache) {
|
||||
|
||||
if (FilePath::isRoot(f)) {
|
||||
# ifdef G3D_WIN32
|
||||
const std::string& winname = toLower(f.substr(0, 1)) + ":\\";
|
||||
return _drives().contains(winname);
|
||||
# else
|
||||
return true;
|
||||
# endif
|
||||
}
|
||||
|
||||
std::string path = FilePath::removeTrailingSlash(f);
|
||||
std::string parentPath = FilePath::parent(path);
|
||||
|
||||
const Dir& entry = getContents(parentPath, ! trustCache);
|
||||
|
||||
if (FilePath::containsWildcards(f)) {
|
||||
if (! entry.exists) {
|
||||
// The directory didn't exist, so neither do its contents
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& pattern = FilePath::baseExt(path);
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
static const int flags = FNM_CASEFOLD;
|
||||
# else
|
||||
static const int flags = 0;
|
||||
# endif
|
||||
|
||||
// See if any element of entry matches the wild card
|
||||
for (int i = 0; i < entry.nodeArray.size(); ++i) {
|
||||
if (FilePath::matches(entry.nodeArray[i].name, pattern, flags)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find a match
|
||||
return false;
|
||||
|
||||
} else {
|
||||
return entry.exists && entry.contains(FilePath::baseExt(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_isDirectory(const std::string& filename) {
|
||||
// TODO: work with zipfiles and cache
|
||||
struct _stat st;
|
||||
const bool exists = _stat(FilePath::removeTrailingSlash(filename).c_str(), &st) != -1;
|
||||
return exists && ((st.st_mode & S_IFDIR) != 0);
|
||||
}
|
||||
|
||||
|
||||
std::string FileSystem::_resolve(const std::string& filename, const std::string& cwd) {
|
||||
if (filename.size() >= 1) {
|
||||
if (isSlash(filename[0])) {
|
||||
// Already resolved
|
||||
return filename;
|
||||
} else {
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
if ((filename.size() >= 2) && (filename[1] == ':')) {
|
||||
// There is a drive spec on the front.
|
||||
if ((filename.size() >= 3) && isSlash(filename[2])) {
|
||||
// Already fully qualified
|
||||
return filename;
|
||||
} else {
|
||||
// The drive spec is relative to the
|
||||
// working directory on that drive.
|
||||
debugAssertM(false, "Files of the form d:path are"
|
||||
" not supported (use a fully qualified"
|
||||
" name).");
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend the working directory.
|
||||
return FilePath::concat(cwd, filename);
|
||||
}
|
||||
|
||||
|
||||
std::string FileSystem::_currentDirectory() {
|
||||
static const int N = 2048;
|
||||
char buffer[N];
|
||||
|
||||
_getcwd(buffer, N);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::_isNewer(const std::string& src, const std::string& dst) {
|
||||
// TODO: work with cache and zipfiles
|
||||
struct _stat sts;
|
||||
bool sexists = _stat(src.c_str(), &sts) != -1;
|
||||
|
||||
struct _stat dts;
|
||||
bool dexists = _stat(dst.c_str(), &dts) != -1;
|
||||
|
||||
return sexists && ((! dexists) || (sts.st_mtime > dts.st_mtime));
|
||||
}
|
||||
|
||||
|
||||
int64 FileSystem::_size(const std::string& filename) {
|
||||
struct stat64 st;
|
||||
int result = stat64(filename.c_str(), &st);
|
||||
|
||||
if (result == -1) {
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
std::string zip, contents;
|
||||
if (zipfileExists(filename, zip, contents)) {
|
||||
int64 requiredMem;
|
||||
|
||||
struct zip *z = zip_open( zip.c_str(), ZIP_CHECKCONS, NULL );
|
||||
debugAssertM(z != NULL, zip + ": zip open failed.");
|
||||
{
|
||||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // Docs unclear if zip_stat_init is required.
|
||||
int success = zip_stat( z, contents.c_str(), ZIP_FL_NOCASE, &info );
|
||||
debugAssertM(success == 0, zip + ": " + contents + ": zip stat failed.");
|
||||
requiredMem = info.size;
|
||||
}
|
||||
zip_close(z);
|
||||
return requiredMem;
|
||||
} else {
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
return -1;
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
}
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
}
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::listHelper(const std::string& shortSpec, const std::string& parentPath, Array<std::string>& result, const ListSettings& settings) {
|
||||
Dir& dir = getContents(parentPath, false);
|
||||
|
||||
if (! dir.exists) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dir.nodeArray.size(); ++i) {
|
||||
Entry& entry = dir.nodeArray[i];
|
||||
// See if it matches the spec
|
||||
if (FilePath::matches(entry.name, shortSpec, settings.caseSensitive)) {
|
||||
|
||||
if ((entry.type == UNKNOWN) && ! (settings.files && settings.directories)) {
|
||||
// Update the type
|
||||
entry.type = isDirectory(FilePath::concat(parentPath, entry.name)) ? DIR_TYPE : FILE_TYPE;
|
||||
}
|
||||
|
||||
if ((settings.files && settings.directories) ||
|
||||
(settings.files && (entry.type == FILE_TYPE)) ||
|
||||
(settings.directories && (entry.type == DIR_TYPE))) {
|
||||
|
||||
if (settings.includeParentPath) {
|
||||
result.append(FilePath::concat(parentPath, entry.name));
|
||||
} else {
|
||||
result.append(entry.name);
|
||||
}
|
||||
}
|
||||
} // match
|
||||
|
||||
if (settings.recursive && (entry.type == DIR_TYPE)) {
|
||||
listHelper(shortSpec, FilePath::concat(parentPath, entry.name), result, settings);
|
||||
}
|
||||
} // for
|
||||
}
|
||||
|
||||
|
||||
void FileSystem::_list(const std::string& spec, Array<std::string>& result, const ListSettings& settings) {
|
||||
const std::string& shortSpec = FilePath::baseExt(spec);
|
||||
const std::string& parentPath = FilePath::parent(spec);
|
||||
|
||||
listHelper(shortSpec, parentPath, result, settings);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
const Array<std::string>& FileSystem::_drives() {
|
||||
if (m_winDrive.length() == 0) {
|
||||
// See http://msdn.microsoft.com/en-us/library/aa364975(VS.85).aspx
|
||||
static const size_t bufSize = 5000;
|
||||
char bufData[bufSize];
|
||||
GetLogicalDriveStringsA(bufSize, bufData);
|
||||
|
||||
// Drive list is a series of NULL-terminated strings, itself terminated with a NULL.
|
||||
for (int i = 0; bufData[i] != '\0'; ++i) {
|
||||
const char* thisString = bufData + i;
|
||||
m_winDrive.append(toLower(thisString));
|
||||
i += strlen(thisString) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return m_winDrive;
|
||||
}
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool FilePath::isRoot(const std::string& f) {
|
||||
# ifdef G3D_WIN32
|
||||
if (f.length() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f[1] == ':') {
|
||||
if (f.length() == 2) {
|
||||
// e.g., "x:"
|
||||
return true;
|
||||
} else if ((f.length() == 3) && isSlash(f[2])) {
|
||||
// e.g., "x:\"
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSlash(f[0]) && isSlash(f[1])) {
|
||||
// e.g., "\\foo\"
|
||||
return true;
|
||||
}
|
||||
# else
|
||||
if (f == "/") {
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::removeTrailingSlash(const std::string& f) {
|
||||
bool removeSlash = ((endsWith(f, "/") || endsWith(f, "\\"))) && ! isRoot(f);
|
||||
|
||||
return removeSlash ? f.substr(0, f.length() - 1) : f;
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::concat(const std::string& dirname, const std::string& file) {
|
||||
// Ensure that the directory ends in a slash
|
||||
if (! dirname.empty() &&
|
||||
! isSlash(dirname[dirname.size() - 1]) &&
|
||||
(dirname[dirname.size() - 1] != ':')) {
|
||||
return dirname + '/' + file;
|
||||
} else {
|
||||
return dirname + file;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::ext(const std::string& filename) {
|
||||
int i = filename.rfind(".");
|
||||
if (i >= 0) {
|
||||
return filename.substr(i + 1, filename.length() - i);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::baseExt(const std::string& filename) {
|
||||
int i = findLastSlash(filename);
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
int j = filename.rfind(":");
|
||||
if ((i == -1) && (j >= 0)) {
|
||||
i = j;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (i == -1) {
|
||||
return filename;
|
||||
} else {
|
||||
return filename.substr(i + 1, filename.length() - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::base(const std::string& path) {
|
||||
std::string filename = baseExt(path);
|
||||
int i = filename.rfind(".");
|
||||
if (i == -1) {
|
||||
// No extension
|
||||
return filename;
|
||||
} else {
|
||||
return filename.substr(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::parent(const std::string& path) {
|
||||
int i = findLastSlash(removeTrailingSlash(path));
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
int j = path.rfind(":");
|
||||
if ((i == -1) && (j >= 0)) {
|
||||
i = j;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (i == -1) {
|
||||
return "";
|
||||
} else {
|
||||
return path.substr(0, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FilePath::containsWildcards(const std::string& filename) {
|
||||
return (filename.find('*') != std::string::npos) || (filename.find('?') != std::string::npos);
|
||||
}
|
||||
|
||||
|
||||
bool FilePath::matches(const std::string& path, const std::string& pattern, bool caseSensitive) {
|
||||
int flags = FNM_PERIOD | FNM_NOESCAPE | FNM_PATHNAME;
|
||||
if (! caseSensitive) {
|
||||
flags |= FNM_CASEFOLD;
|
||||
}
|
||||
return g3dfnmatch(pattern.c_str(), path.c_str(), flags) == 0;
|
||||
}
|
||||
|
||||
|
||||
static int fixslash(int c) {
|
||||
return (c == '\\') ? '/' : c;
|
||||
}
|
||||
|
||||
|
||||
std::string FilePath::canonicalize(std::string x) {
|
||||
std::transform(x.begin(), x.end(), x.begin(), fixslash);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
void FilePath::parse
|
||||
(const std::string& filename,
|
||||
std::string& root,
|
||||
Array<std::string>& path,
|
||||
std::string& base,
|
||||
std::string& ext) {
|
||||
|
||||
std::string f = filename;
|
||||
|
||||
root = "";
|
||||
path.clear();
|
||||
base = "";
|
||||
ext = "";
|
||||
|
||||
if (f == "") {
|
||||
// Empty filename
|
||||
return;
|
||||
}
|
||||
|
||||
// See if there is a root/drive spec.
|
||||
if ((f.size() >= 2) && (f[1] == ':')) {
|
||||
|
||||
if ((f.size() > 2) && isSlash(f[2])) {
|
||||
|
||||
// e.g. c:\foo
|
||||
root = f.substr(0, 3);
|
||||
f = f.substr(3, f.size() - 3);
|
||||
|
||||
} else {
|
||||
|
||||
// e.g. c:foo
|
||||
root = f.substr(2);
|
||||
f = f.substr(2, f.size() - 2);
|
||||
|
||||
}
|
||||
|
||||
} else if ((f.size() >= 2) & isSlash(f[0]) && isSlash(f[1])) {
|
||||
|
||||
// e.g. //foo
|
||||
root = f.substr(0, 2);
|
||||
f = f.substr(2, f.size() - 2);
|
||||
|
||||
} else if (isSlash(f[0])) {
|
||||
|
||||
root = f.substr(0, 1);
|
||||
f = f.substr(1, f.size() - 1);
|
||||
|
||||
}
|
||||
|
||||
// Pull the extension off
|
||||
{
|
||||
// Find the period
|
||||
size_t i = f.rfind('.');
|
||||
|
||||
if (i != std::string::npos) {
|
||||
// Make sure it is after the last slash!
|
||||
size_t j = iMax(f.rfind('/'), f.rfind('\\'));
|
||||
if ((j == std::string::npos) || (i > j)) {
|
||||
ext = f.substr(i + 1, f.size() - i - 1);
|
||||
f = f.substr(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pull the basename off
|
||||
{
|
||||
// Find the last slash
|
||||
size_t i = iMax(f.rfind('/'), f.rfind('\\'));
|
||||
|
||||
if (i == std::string::npos) {
|
||||
|
||||
// There is no slash; the basename is the whole thing
|
||||
base = f;
|
||||
f = "";
|
||||
|
||||
} else if ((i != std::string::npos) && (i < f.size() - 1)) {
|
||||
|
||||
base = f.substr(i + 1, f.size() - i - 1);
|
||||
f = f.substr(0, i);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Parse what remains into path.
|
||||
size_t prev, cur = 0;
|
||||
|
||||
while (cur < f.size()) {
|
||||
prev = cur;
|
||||
|
||||
// Allow either slash
|
||||
size_t i = f.find('/', prev + 1);
|
||||
size_t j = f.find('\\', prev + 1);
|
||||
if (i == std::string::npos) {
|
||||
i = f.size();
|
||||
}
|
||||
|
||||
if (j == std::string::npos) {
|
||||
j = f.size();
|
||||
}
|
||||
|
||||
cur = iMin(i, j);
|
||||
|
||||
if (cur == std::string::npos) {
|
||||
cur = f.size();
|
||||
}
|
||||
|
||||
path.append(f.substr(prev, cur - prev));
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
/*
|
||||
@file GCamera.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@author Jeff Marsceill, 08jcm@williams.edu
|
||||
|
||||
@created 2005-07-20
|
||||
@edited 2009-11-24
|
||||
@edited 2010-02-22
|
||||
*/
|
||||
#include "G3D/GCamera.h"
|
||||
#include "G3D/platform.h"
|
||||
|
|
@ -45,6 +45,8 @@ GCamera::GCamera(const Any& any) {
|
|||
m_nearPlaneZ = it->value;
|
||||
} else if (k == "FARPLANEZ") {
|
||||
m_farPlaneZ = it->value;
|
||||
} else if (k == "PIXELOFFSET") {
|
||||
m_pixelOffset = it->value;
|
||||
} else {
|
||||
any.verify(false, std::string("Illegal key in table: ") + it->key);
|
||||
}
|
||||
|
|
@ -61,6 +63,7 @@ GCamera::operator Any() const {
|
|||
any.set("nearPlaneZ", nearPlaneZ());
|
||||
any.set("farPlaneZ", farPlaneZ());
|
||||
any.set("coordinateFrame", coordinateFrame());
|
||||
any.set("pixelOffset", pixelOffset());
|
||||
|
||||
return any;
|
||||
}
|
||||
|
|
@ -68,7 +71,7 @@ GCamera::operator Any() const {
|
|||
|
||||
GCamera::GCamera() {
|
||||
setNearPlaneZ(-0.2f);
|
||||
setFarPlaneZ(-100.0f);
|
||||
setFarPlaneZ(-150.0f);
|
||||
setFieldOfView((float)toRadians(90.0f), HORIZONTAL);
|
||||
}
|
||||
|
||||
|
|
@ -171,8 +174,8 @@ void GCamera::getProjectPixelMatrix(const Rect2D& viewport, Matrix4& P) const {
|
|||
float sx = screenWidth / 2.0;
|
||||
float sy = screenHeight / 2.0;
|
||||
|
||||
P = Matrix4(sx, 0, 0, sx + viewport.x0(),
|
||||
0, -sy, 0, sy + viewport.y0(),
|
||||
P = Matrix4(sx, 0, 0, sx + viewport.x0() - m_pixelOffset.x,
|
||||
0, -sy, 0, sy + viewport.y0() + m_pixelOffset.y,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1) * P;
|
||||
}
|
||||
|
|
@ -185,24 +188,28 @@ void GCamera::getProjectUnitMatrix(const Rect2D& viewport, Matrix4& P) const {
|
|||
|
||||
float r, l, t, b, n, f, x, y;
|
||||
|
||||
float s = 1.0f;
|
||||
if (m_direction == VERTICAL) {
|
||||
y = -m_nearPlaneZ * tan(m_fieldOfView / 2);
|
||||
x = y * (screenWidth / screenHeight);
|
||||
s = screenHeight;
|
||||
} else { //m_direction == HORIZONTAL
|
||||
x = -m_nearPlaneZ * tan(m_fieldOfView / 2);
|
||||
y = x * (screenHeight / screenWidth);
|
||||
s = screenWidth;
|
||||
}
|
||||
|
||||
n = -m_nearPlaneZ;
|
||||
f = -m_farPlaneZ;
|
||||
r = x;
|
||||
l = -x;
|
||||
t = y;
|
||||
b = -y;
|
||||
r = x - m_pixelOffset.x/s;
|
||||
l = -x - m_pixelOffset.x/s;
|
||||
t = y + m_pixelOffset.y/s;
|
||||
b = -y + m_pixelOffset.y/s;
|
||||
|
||||
P = Matrix4::perspectiveProjection(l, r, b, t, n, f);
|
||||
}
|
||||
|
||||
|
||||
Vector3 GCamera::projectUnit(const Vector3& point, const Rect2D& viewport) const {
|
||||
Matrix4 M;
|
||||
getProjectUnitMatrix(viewport, M);
|
||||
|
|
@ -244,7 +251,7 @@ Vector3 GCamera::unproject(const Vector3& v, const Rect2D& viewport) const {
|
|||
z = 1.0f / ((((1.0f / f) - (1.0f / n)) * v.z) + 1.0f / n);
|
||||
}
|
||||
|
||||
const Ray& ray = worldRay(v.x, v.y, viewport);
|
||||
const Ray& ray = worldRay(v.x - m_pixelOffset.x, v.y - m_pixelOffset.y, viewport);
|
||||
|
||||
// Find out where the ray reaches the specified depth.
|
||||
const Vector3& out = ray.origin() + ray.direction() * -z / (ray.direction().dot(m_cframe.lookVector()));
|
||||
|
|
@ -481,6 +488,7 @@ void GCamera::serialize(BinaryOutput& bo) const {
|
|||
bo.writeFloat32(farPlaneZ());
|
||||
m_cframe.serialize(bo);
|
||||
bo.writeInt8(m_direction);
|
||||
m_pixelOffset.serialize(bo);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -492,6 +500,7 @@ void GCamera::deserialize(BinaryInput& bi) {
|
|||
debugAssert(m_farPlaneZ < 0.0f);
|
||||
m_cframe.deserialize(bi);
|
||||
m_direction = (FOVDirection)bi.readInt8();
|
||||
m_pixelOffset.deserialize(bi);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
\file GImage.cpp
|
||||
\author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
Copyright 2002-2010, Morgan McGuire
|
||||
|
|
@ -639,7 +639,7 @@ void GImage::rotate90CW(int numTimes) {
|
|||
for (int j = 0; j < numTimes; ++j) {
|
||||
{
|
||||
uint8* temp = old;
|
||||
uint8* old = m_byte;
|
||||
old = m_byte;
|
||||
m_byte = temp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GImage_bayer.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GImage_bmp.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
namespace G3D {
|
||||
|
||||
#ifndef G3D_WIN32
|
||||
/**
|
||||
/*
|
||||
This is used by the Windows bitmap I/O.
|
||||
*/
|
||||
static const int BI_RGB = 0;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GImage_jpeg.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
|
|
@ -26,7 +26,7 @@ namespace G3D {
|
|||
|
||||
const int jpegQuality = 96;
|
||||
|
||||
/**
|
||||
/*
|
||||
The IJG library needs special setup for compress/decompressing
|
||||
from memory. These classes provide them.
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
typedef memory_destination_mgr* mem_dest_ptr;
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void init_destination (
|
||||
|
|
@ -56,7 +56,7 @@ static void init_destination (
|
|||
dest->count=0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static boolean empty_output_buffer (
|
||||
|
|
@ -70,7 +70,7 @@ static boolean empty_output_buffer (
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void term_destination (
|
||||
|
|
@ -80,7 +80,7 @@ static void term_destination (
|
|||
dest->count = dest->size - dest->pub.free_in_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void jpeg_memory_dest (
|
||||
|
|
@ -111,7 +111,7 @@ static void jpeg_memory_dest (
|
|||
|
||||
#define INPUT_BUF_SIZE 4096
|
||||
|
||||
/**
|
||||
/*
|
||||
Structure dictated by IJG.
|
||||
*/
|
||||
class memory_source_mgr {
|
||||
|
|
@ -127,7 +127,7 @@ public:
|
|||
typedef memory_source_mgr* mem_src_ptr;
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void init_source(
|
||||
|
|
@ -139,7 +139,7 @@ static void init_source(
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static boolean fill_input_buffer(
|
||||
|
|
@ -168,7 +168,7 @@ static boolean fill_input_buffer(
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void skip_input_data(
|
||||
|
|
@ -190,7 +190,7 @@ static void skip_input_data(
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void term_source (
|
||||
|
|
@ -200,7 +200,7 @@ static void term_source (
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Signature dictated by IJG.
|
||||
*/
|
||||
static void jpeg_memory_src (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GImage_png.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
|
|
@ -71,10 +71,20 @@ void png_warning(
|
|||
void GImage::encodePNG(
|
||||
BinaryOutput& out) const {
|
||||
|
||||
debugAssert( m_channels == 1 || m_channels == 3 || m_channels == 4 );
|
||||
if (! (m_channels == 1 || m_channels == 3 || m_channels == 4)) {
|
||||
throw GImage::Error(format("Illegal channels for PNG: %d", m_channels), out.getFilename());
|
||||
}
|
||||
if (m_width <= 0) {
|
||||
throw GImage::Error(format("Illegal width for PNG: %d", m_width), out.getFilename());
|
||||
}
|
||||
if (m_height <= 0) {
|
||||
throw GImage::Error(format("Illegal height for PNG: %d", m_height), out.getFilename());
|
||||
}
|
||||
|
||||
if (m_height > (int)(PNG_UINT_32_MAX / png_sizeof(png_bytep)))
|
||||
// PNG library requires that the height * pointer size fit within an int
|
||||
if (png_uint_32(m_height) * png_sizeof(png_bytep) > PNG_UINT_32_MAX) {
|
||||
throw GImage::Error("Unsupported PNG height.", out.getFilename());
|
||||
}
|
||||
|
||||
out.setEndian(G3D_LITTLE_ENDIAN);
|
||||
|
||||
|
|
@ -184,7 +194,7 @@ void GImage::decodePNG(
|
|||
int bit_depth, color_type, interlace_type;
|
||||
// this will validate the data it extracts from info_ptr
|
||||
png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type,
|
||||
&interlace_type, int_p_NULL, int_p_NULL);
|
||||
&interlace_type, NULL, NULL);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
|
|
@ -206,7 +216,7 @@ void GImage::decodePNG(
|
|||
|
||||
//Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
|
||||
png_set_gray_1_2_4_to_8(png_ptr);
|
||||
png_set_expand(png_ptr);
|
||||
}
|
||||
|
||||
//Expand paletted or RGB images with transparency to full alpha channels
|
||||
|
|
@ -253,7 +263,7 @@ void GImage::decodePNG(
|
|||
for (uint32 pass = 0; pass < number_passes; ++pass) {
|
||||
for (uint32 y = 0; y < (uint32)m_height; ++y) {
|
||||
png_bytep rowPointer = &m_byte[m_width * m_channels * y];
|
||||
png_read_rows(png_ptr, &rowPointer, png_bytepp_NULL, 1);
|
||||
png_read_rows(png_ptr, &rowPointer, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GImage_ppm.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
|
|
@ -183,7 +183,7 @@ void GImage::decodePPM(
|
|||
int w, h;
|
||||
|
||||
input.readBytes(head, 2);
|
||||
if (head[0] != 'P' || (head[1] != '6') && (head[1] != '5')) {
|
||||
if (head[0] != 'P' || ((head[1] != '6') && (head[1] != '5'))) {
|
||||
throw GImage::Error("Invalid PPM Header.", input.getFilename());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GImage_tga.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2002-05-27
|
||||
|
|
@ -94,6 +94,20 @@ void GImage::encodeTGA(
|
|||
out.writeString("TRUEVISION-XFILE ");
|
||||
}
|
||||
|
||||
inline static void readBGR(uint8* byte, BinaryInput& bi) {
|
||||
int b = bi.readUInt8();
|
||||
int g = bi.readUInt8();
|
||||
int r = bi.readUInt8();
|
||||
|
||||
byte[0] = r;
|
||||
byte[1] = g;
|
||||
byte[2] = b;
|
||||
}
|
||||
|
||||
inline static void readBGRA(uint8* byte, BinaryInput& bi) {
|
||||
readBGR(byte, bi);
|
||||
byte[3] = bi.readUInt8();
|
||||
}
|
||||
|
||||
void GImage::decodeTGA(
|
||||
BinaryInput& input) {
|
||||
|
|
@ -117,8 +131,8 @@ void GImage::decodeTGA(
|
|||
(void)colorMapType;
|
||||
|
||||
// 2 is the type supported by this routine.
|
||||
if (imageType != 2) {
|
||||
throw Error("TGA images must be type 2 (Uncompressed truecolor)", input.getFilename());
|
||||
if (imageType != 2 && imageType != 10) {
|
||||
throw Error("TGA images must be type 2 (Uncompressed truecolor) or 10 (Run-length truecolor)", input.getFilename());
|
||||
}
|
||||
|
||||
// Color map specification
|
||||
|
|
@ -159,34 +173,63 @@ void GImage::decodeTGA(
|
|||
int x;
|
||||
int y;
|
||||
|
||||
if (m_channels == 3) {
|
||||
if (imageType == 2) {
|
||||
// Uncompressed
|
||||
if (m_channels == 3) {
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (x = 0; x < m_width; ++x) {
|
||||
int i = (x + y * m_width) * 3;
|
||||
readBGR(m_byte + i, input);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (x = 0; x < m_width; ++x) {
|
||||
int i = (x + y * m_width) * 4;
|
||||
readBGRA(m_byte + i, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (imageType == 10) {
|
||||
|
||||
// Run-length encoded
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (x = 0; x < m_width; ++x) {
|
||||
int b = input.readUInt8();
|
||||
int g = input.readUInt8();
|
||||
int r = input.readUInt8();
|
||||
|
||||
int i = (x + y * m_width) * 3;
|
||||
m_byte[i + 0] = r;
|
||||
m_byte[i + 1] = g;
|
||||
m_byte[i + 2] = b;
|
||||
}
|
||||
for (int x = 0; x < m_width; /* intentionally no x increment */) {
|
||||
// The specification guarantees that no packet will wrap past the end of a row
|
||||
const uint8 repetitionCount = input.readUInt8();
|
||||
const uint8 numValues = (repetitionCount & (~128)) + 1;
|
||||
int byteOffset = (x + y * m_width) * 3;
|
||||
|
||||
if (repetitionCount & 128) {
|
||||
// When the high bit is 1, this is a run-length packet
|
||||
if (m_channels == 3) {
|
||||
Color3uint8 value;
|
||||
readBGR((uint8*)(&value), input);
|
||||
for (int i = 0; i < numValues; ++i, ++x) {
|
||||
for (int b = 0; b < 3; ++b, ++byteOffset) {
|
||||
m_byte[byteOffset] = value[b];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Color4uint8 value;
|
||||
readBGRA((uint8*)(&value), input);
|
||||
for (int i = 0; i < numValues; ++i, ++x) {
|
||||
for (int b = 0; b < 3; ++b, ++byteOffset) {
|
||||
m_byte[byteOffset] = value[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// When the high bit is 0, this is a raw packet
|
||||
for (int i = 0; i < numValues; ++i, ++x, byteOffset += m_channels) {
|
||||
readBGR(m_byte + byteOffset, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = m_height - 1; y >= 0; --y) {
|
||||
for (x = 0; x < m_width; ++x) {
|
||||
int b = input.readUInt8();
|
||||
int g = input.readUInt8();
|
||||
int r = input.readUInt8();
|
||||
int a = input.readUInt8();
|
||||
|
||||
int i = (x + y * m_width) * 4;
|
||||
m_byte[i + 0] = r;
|
||||
m_byte[i + 1] = g;
|
||||
m_byte[i + 2] = b;
|
||||
m_byte[i + 3] = a;
|
||||
}
|
||||
}
|
||||
alwaysAssertM(false, "Unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GLight.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
@ -19,6 +19,8 @@ GLight::GLight(const Any& any) {
|
|||
|
||||
if (any.type() == Any::TABLE) {
|
||||
*this = GLight();
|
||||
Vector3 spotTarget;
|
||||
bool hasSpotTarget = false;
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& key = toLower(it->key);
|
||||
if (key == "position") {
|
||||
|
|
@ -26,7 +28,10 @@ GLight::GLight(const Any& any) {
|
|||
} else if (key == "rightdirection") {
|
||||
rightDirection = it->value;
|
||||
} else if (key == "spotdirection") {
|
||||
spotDirection = it->value;
|
||||
spotDirection = Vector3(it->value).directionOrZero();
|
||||
} else if (key == "spottarget") {
|
||||
spotTarget = it->value;
|
||||
hasSpotTarget = true;
|
||||
} else if (key == "spotcutoff") {
|
||||
spotCutoff = it->value.number();
|
||||
} else if (key == "spotsquare") {
|
||||
|
|
@ -47,6 +52,9 @@ GLight::GLight(const Any& any) {
|
|||
any.verify(false, "Illegal key: " + it->key);
|
||||
}
|
||||
}
|
||||
if (hasSpotTarget) {
|
||||
spotDirection = (spotTarget - position.xyz()).direction();
|
||||
}
|
||||
} else if (toLower(any.name()) == "glight::directional") {
|
||||
|
||||
*this = directional(any[0], any[1],
|
||||
|
|
@ -67,9 +75,9 @@ GLight::GLight(const Any& any) {
|
|||
*this = spot(any[0], any[1], any[2], any[3],
|
||||
(any.size() > 4) ? any[4] : Any(1),
|
||||
(any.size() > 5) ? any[5] : Any(0),
|
||||
(any.size() > 6) ? any[6] : Any(0.5f),
|
||||
(any.size() > 7) ? any[5] : Any(true),
|
||||
(any.size() > 8) ? any[6] : Any(true));
|
||||
(any.size() > 6) ? any[6] : Any(0),
|
||||
(any.size() > 7) ? any[7] : Any(true),
|
||||
(any.size() > 8) ? any[8] : Any(true));
|
||||
} else {
|
||||
any.verify(false, "Unrecognized name");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GThread.cpp
|
||||
|
||||
GThread class.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file GUniqueID.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Image1.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Image1uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Image3.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Image3uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Image4.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Image4uint8.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
/**
|
||||
/*
|
||||
@file ImageFormat.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2003-05-23
|
||||
@edited 2009-12-10
|
||||
@edited 2010-03-30
|
||||
*/
|
||||
|
||||
#include "GLG3D/glheaders.h"
|
||||
|
|
@ -130,13 +130,19 @@ const ImageFormat* ImageFormat::stencil(int bits) {
|
|||
"RGB8I",
|
||||
"RGB8UI",
|
||||
|
||||
"RGBA8UI",
|
||||
|
||||
"ARGB8",
|
||||
"BGR8",
|
||||
|
||||
"R8",
|
||||
|
||||
"RG8",
|
||||
"RG8I",
|
||||
"RG8UI",
|
||||
|
||||
"RG16F",
|
||||
|
||||
"RGBA8",
|
||||
"RGBA16",
|
||||
"RGBA16F",
|
||||
|
|
@ -287,6 +293,9 @@ const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
|
|||
case ImageFormat::CODE_BGR8:
|
||||
return ImageFormat::BGR8();
|
||||
|
||||
case ImageFormat::CODE_R8:
|
||||
return ImageFormat::R8();
|
||||
|
||||
case ImageFormat::CODE_RG8:
|
||||
return ImageFormat::RG8();
|
||||
|
||||
|
|
@ -296,6 +305,9 @@ const ImageFormat* ImageFormat::fromCode(ImageFormat::Code code) {
|
|||
case ImageFormat::CODE_RG8UI:
|
||||
return ImageFormat::RG8UI();
|
||||
|
||||
case ImageFormat::CODE_RG16F:
|
||||
return ImageFormat::RG16F();
|
||||
|
||||
case ImageFormat::CODE_RGBA8:
|
||||
return ImageFormat::RGBA8();
|
||||
|
||||
|
|
@ -474,11 +486,16 @@ DEFINE_TEXTUREFORMAT_METHOD(LA32F, 2, UNCOMP_FORMAT, GL_LUMINANCE_ALPHA32
|
|||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(BGR8, 3, UNCOMP_FORMAT, GL_RGB8, GL_BGR, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_BGR8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(R8, 1, UNCOMP_FORMAT, GL_R8, GL_RED, 0, 0, 8, 0, 0, 0, 0, 8, 8, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_R8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8, 2, UNCOMP_FORMAT, GL_RG8, GL_RG, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8I, 2, UNCOMP_FORMAT, GL_RG8I, GL_RG, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8I, ImageFormat::COLOR_SPACE_RGB);
|
||||
// The base format for integer formats must be *_INTEGER even though the spec doesn't state this
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8I, 2, UNCOMP_FORMAT, GL_RG8I, GL_RG_INTEGER, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8I, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8UI, 2, UNCOMP_FORMAT, GL_RG8UI, GL_RG, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG8UI, 2, UNCOMP_FORMAT, GL_RG8UI, GL_RG_INTEGER, 0, 0, 8, 8, 0, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RG8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RG16F, 2, UNCOMP_FORMAT, GL_RG16F, GL_RG, 0, 0, 16, 16, 0, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RG16F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB5, 3, UNCOMP_FORMAT, GL_RGB5, GL_RGBA, 0, 0, 5, 5, 5, 0, 0, 16, 16, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB5, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
|
|
@ -504,7 +521,8 @@ DEFINE_TEXTUREFORMAT_METHOD(RGBA16F, 4, UNCOMP_FORMAT, GL_RGBA16F_ARB,
|
|||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA32F, 4, UNCOMP_FORMAT, GL_RGBA32F_ARB, GL_RGBA, 0, 32, 32, 32, 32, 0, 0, 32*4, 32*4, GL_FLOAT, CLEAR_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGBA32F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA32UI, 4, UNCOMP_FORMAT, GL_RGBA32UI, GL_RGBA, 0, 32, 32, 32, 32, 0, 0, 32*4, 32*4, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA32UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
// The base format for integer formats must be *_INTEGER even though the spec doesn't state this
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA32UI, 4, UNCOMP_FORMAT, GL_RGBA32UI, GL_RGBA_INTEGER, 0, 32, 32, 32, 32, 0, 0, 32*4, 32*4, GL_UNSIGNED_INT, CLEAR_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA32UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
// Unsigned
|
||||
DEFINE_TEXTUREFORMAT_METHOD(R11G11B10F, 3, UNCOMP_FORMAT, GL_R11F_G11F_B10F_EXT, GL_RGB, 0, 0, 11, 11, 10, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_R11G11B10F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
|
@ -512,9 +530,12 @@ DEFINE_TEXTUREFORMAT_METHOD(R11G11B10F, 3, UNCOMP_FORMAT, GL_R11F_G11F_B10F_EX
|
|||
// Unsigned
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB9E5F, 3, UNCOMP_FORMAT, GL_RGB9_E5_EXT, GL_RGB, 0, 0, 14, 14, 14, 0, 0, 32, 32, GL_FLOAT, OPAQUE_FORMAT, FLOAT_FORMAT, ImageFormat::CODE_RGB9E5F, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8I, 3, UNCOMP_FORMAT, GL_RGB8I_EXT, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8I, ImageFormat::COLOR_SPACE_RGB);
|
||||
// The base format for integer formats must be *_INTEGER even though the spec doesn't state this
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8I, 3, UNCOMP_FORMAT, GL_RGB8I_EXT, GL_RGB_INTEGER, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8I, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8UI, 3, UNCOMP_FORMAT, GL_RGB8UI_EXT, GL_RGB, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB8UI, 3, UNCOMP_FORMAT, GL_RGB8UI_EXT, GL_RGB_INTEGER, 0, 0, 8, 8, 8, 0, 0, 32, 24, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGBA8UI, 4, UNCOMP_FORMAT, GL_RGBA8UI_EXT, GL_RGBA_INTEGER, 0, 0, 8, 8, 8, 8, 0, 32, 32, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGBA8UI, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
||||
|
||||
DEFINE_TEXTUREFORMAT_METHOD(RGB_DXT1, 3, COMP_FORMAT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, 0, 0, 0, 0, 0, 0, 0, 64, 64, GL_UNSIGNED_BYTE, OPAQUE_FORMAT, INT_FORMAT, ImageFormat::CODE_RGB_DXT1, ImageFormat::COLOR_SPACE_RGB);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Intersect.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Line.cpp
|
||||
|
||||
Line class
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file LineSegment.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/**
|
||||
/*
|
||||
@file Log.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2001-08-04
|
||||
@edited 2009-01-15
|
||||
@edited 2010-01-15
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
#include "G3D/format.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
#include <time.h>
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
|
|
@ -43,7 +44,7 @@ Log::Log(const std::string& filename, int stripFromStackBottom) :
|
|||
|
||||
this->filename = filename;
|
||||
|
||||
logFile = fopen(filename.c_str(), "w");
|
||||
logFile = FileSystem::fopen(filename.c_str(), "w");
|
||||
|
||||
if (logFile == NULL) {
|
||||
std::string drive, base, ext;
|
||||
|
|
@ -58,7 +59,7 @@ Log::Log(const std::string& filename, int stripFromStackBottom) :
|
|||
logName = std::string("/tmp/") + logName;
|
||||
#endif
|
||||
|
||||
logFile = fopen(logName.c_str(), "w");
|
||||
logFile = FileSystem::fopen(logName.c_str(), "w");
|
||||
}
|
||||
|
||||
// Use a large buffer (although we flush in logPrintf)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Matrix.cpp
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Matrix3.cpp
|
||||
|
||||
3x3 matrix class
|
||||
|
|
@ -29,11 +29,17 @@ const float Matrix3::EPSILON = 1e-06f;
|
|||
Matrix3::Matrix3(const Any& any) {
|
||||
any.verifyName("Matrix3");
|
||||
any.verifyType(Any::ARRAY);
|
||||
any.verifySize(9);
|
||||
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
elt[r][c] = any[r * 3 + c];
|
||||
if (any.nameEquals("Matrix3::fromAxisAngle")) {
|
||||
any.verifySize(2);
|
||||
*this = Matrix3::fromAxisAngle(any[0], any[1].number());
|
||||
} else {
|
||||
any.verifySize(9);
|
||||
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
elt[r][c] = any[r * 3 + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Matrix4.cpp
|
||||
|
||||
|
||||
|
|
@ -44,7 +44,12 @@ Matrix4::Matrix4(const Any& any) {
|
|||
} else {
|
||||
any.verify(false, "Matrix4::scale() takes either 1 or 3 arguments");
|
||||
}
|
||||
} else {
|
||||
} else if (name == "matrix4::translation") {
|
||||
if (any.size() == 3) {
|
||||
*this = translation(any[0], any[1], any[2]);
|
||||
} else {
|
||||
any.verify(false, "Matrix4::translation() takes either 1 or 3 arguments");
|
||||
} } else {
|
||||
any.verify(false, "Expected Matrix4 constructor");
|
||||
}
|
||||
}
|
||||
|
|
@ -253,7 +258,7 @@ Matrix4::Matrix4(
|
|||
elt[3][0] = r4c1; elt[3][1] = r4c2; elt[3][2] = r4c3; elt[3][3] = r4c4;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
init should be <B>row major</B>.
|
||||
*/
|
||||
Matrix4::Matrix4(const float* init) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file MemoryManager.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file MeshAlg.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
/*
|
||||
@file MeshAlgAdjacency.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2003-09-14
|
||||
@edited 2009-04-26
|
||||
@edited 2010-04-26
|
||||
|
||||
Copyright 2000-2009, Morgan McGuire.
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
|
||||
*/
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
#include "G3D/Set.h"
|
||||
#include "G3D/Stopwatch.h"
|
||||
#include "G3D/SmallArray.h"
|
||||
#include "G3D/AreaMemoryManager.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
|
@ -43,6 +44,11 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
MeshEdgeTable() {
|
||||
AreaMemoryManager::Ref mm = AreaMemoryManager::create();
|
||||
table.clearAndSetMemoryManager(mm);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
table.clear();
|
||||
}
|
||||
|
|
@ -51,7 +57,7 @@ public:
|
|||
table.resize(maxV);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
Inserts the faceIndex into the edge's face list.
|
||||
The index may be a negative number indicating a backface.
|
||||
|
||||
|
|
@ -137,7 +143,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Assigns the edge index into the next unassigned edge
|
||||
index. The edge index may be negative, indicating
|
||||
a reverse edge.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file MeshAlgWeld.cpp
|
||||
|
||||
The MeshAlg::computeWeld method.
|
||||
|
|
@ -53,7 +53,7 @@ public:
|
|||
Array<int>& _toOld,
|
||||
double _radius);
|
||||
|
||||
/**
|
||||
/*
|
||||
Computes the grid index from an ordinate.
|
||||
*/
|
||||
void toGridCoords(Vector3 v, int& x, int& y, int& z) const;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file MeshBuilder.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file NetMessage.cpp
|
||||
|
||||
@maintainer Morgan McGuire, morgan@cs.brown.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file NetworkDevice.cpp
|
||||
|
||||
@maintainer Morgan McGuire, morgan@cs.brown.edu
|
||||
|
|
@ -6,8 +6,6 @@
|
|||
@edited 2006-02-24
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/NetworkDevice.h"
|
||||
|
|
@ -18,94 +16,8 @@
|
|||
#include "G3D/G3DGameUnits.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/debug.h"
|
||||
#include "G3D/networkHelpers.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#if defined(G3D_LINUX) || defined(G3D_OSX) || defined(G3D_FREEBSD)
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <ifaddrs.h>
|
||||
# include <netinet/in.h>
|
||||
# include <net/if.h>
|
||||
# ifdef __linux__
|
||||
# include <sys/ioctl.h>
|
||||
# include <netinet/in.h>
|
||||
# include <unistd.h>
|
||||
# include <string.h>
|
||||
// Match Linux to FreeBSD
|
||||
# define AF_LINK AF_PACKET
|
||||
# else
|
||||
# include <net/if_dl.h>
|
||||
# include <sys/sockio.h>
|
||||
# endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define _alloca alloca
|
||||
|
||||
/** Define an error code for non-windows platforms. */
|
||||
int WSAGetLastError() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define SOCKET_ERROR -1
|
||||
|
||||
static std::string socketErrorCode(int code) {
|
||||
return G3D::format("CODE %d: %s\n", code, strerror(code));
|
||||
}
|
||||
|
||||
static std::string socketErrorCode() {
|
||||
return socketErrorCode(errno);
|
||||
}
|
||||
|
||||
static const int WSAEWOULDBLOCK = -100;
|
||||
|
||||
typedef int SOCKET;
|
||||
typedef struct sockaddr_in SOCKADDR_IN;
|
||||
|
||||
#else
|
||||
|
||||
// Windows
|
||||
static std::string socketErrorCode(int code) {
|
||||
LPTSTR formatMsg = NULL;
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
code,
|
||||
0,
|
||||
(LPTSTR)&formatMsg,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
return G3D::format("CODE %d: %s\n", code, formatMsg);
|
||||
}
|
||||
|
||||
static std::string socketErrorCode() {
|
||||
return socketErrorCode(GetLastError());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _SOCKLEN_T
|
||||
# if defined(G3D_WIN32) || defined(G3D_OSX)
|
||||
typedef int socklen_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
|
@ -666,7 +578,7 @@ bool Conduit::messageWaiting() {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Increases the send and receive sizes of a socket to 2 MB from 8k
|
||||
*/
|
||||
static void increaseBufferSize(SOCKET sock) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
/**
|
||||
/*
|
||||
@file PhysicsFrame.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2002-07-09
|
||||
@edited 2006-01-25
|
||||
@edited 2010-03-25
|
||||
*/
|
||||
|
||||
#include "G3D/platform.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/PhysicsFrame.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
|
@ -28,6 +30,37 @@ PhysicsFrame::PhysicsFrame(
|
|||
}
|
||||
|
||||
|
||||
PhysicsFrame::PhysicsFrame(const Any& a) {
|
||||
const std::string& n = toLower(a.name());
|
||||
*this = PhysicsFrame();
|
||||
|
||||
if (beginsWith(n, "vector3")) {
|
||||
*this = PhysicsFrame(Vector3(a));
|
||||
} else if (beginsWith(n, "matrix3")) {
|
||||
*this = PhysicsFrame(Matrix3(a));
|
||||
} else if (beginsWith(n, "cframe") || beginsWith(n, "coordinateframe")) {
|
||||
*this = PhysicsFrame(CoordinateFrame(a));
|
||||
} else if (beginsWith(n, "pframe") || beginsWith(n, "physicsframe")) {
|
||||
if (a.type() == Any::ARRAY) {
|
||||
a.verifySize(2);
|
||||
rotation = a[0];
|
||||
translation = a[1];
|
||||
} else {
|
||||
for (Any::AnyTable::Iterator it = a.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& n = toLower(it->key);
|
||||
if (n == "translation") {
|
||||
translation = it->value;
|
||||
} else if (n == "rotation") {
|
||||
rotation = it->value;
|
||||
} else {
|
||||
a.verify(false, "Illegal table key: " + it->key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PhysicsFrame PhysicsFrame::operator*(const PhysicsFrame& other) const {
|
||||
PhysicsFrame result;
|
||||
|
||||
|
|
@ -38,7 +71,7 @@ PhysicsFrame PhysicsFrame::operator*(const PhysicsFrame& other) const {
|
|||
}
|
||||
|
||||
|
||||
CoordinateFrame PhysicsFrame::toCoordinateFrame() const {
|
||||
PhysicsFrame::operator CoordinateFrame() const {
|
||||
CoordinateFrame f;
|
||||
|
||||
f.translation = translation;
|
||||
|
|
|
|||
80
dep/src/g3dlite/PhysicsFrameSpline.cpp
Normal file
80
dep/src/g3dlite/PhysicsFrameSpline.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
\file PhysicsFrameSpline.cpp
|
||||
|
||||
\author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
*/
|
||||
#include "G3D/PhysicsFrameSpline.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
PhysicsFrameSpline::PhysicsFrameSpline() {}
|
||||
|
||||
PhysicsFrameSpline::PhysicsFrameSpline(const Any& any) {
|
||||
*this = any;
|
||||
}
|
||||
|
||||
PhysicsFrameSpline& PhysicsFrameSpline::operator=(const Any& any) {
|
||||
const std::string& n = toLower(any.name());
|
||||
*this = PhysicsFrameSpline();
|
||||
|
||||
if (n == "physicsframespline" || n == "pframespline") {
|
||||
any.verifyName("PhysicsFrameSpline", "PFrameSpline");
|
||||
|
||||
for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
|
||||
const std::string& k = toLower(it->key);
|
||||
if (k == "cyclic") {
|
||||
cyclic = it->value;
|
||||
} else if (k == "control") {
|
||||
const Any& v = it->value;
|
||||
v.verifyType(Any::ARRAY);
|
||||
control.resize(v.size());
|
||||
for (int i = 0; i < control.size(); ++i) {
|
||||
control[i] = v[i];
|
||||
}
|
||||
if (! any.containsKey("time")) {
|
||||
time.resize(control.size());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
time[i] = i;
|
||||
}
|
||||
}
|
||||
} else if (k == "finalinterval") {
|
||||
finalInterval = it->value;
|
||||
} else if (k == "time") {
|
||||
const Any& v = it->value;
|
||||
v.verifyType(Any::ARRAY);
|
||||
time.resize(v.size());
|
||||
for (int i = 0; i < time.size(); ++i) {
|
||||
time[i] = v[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Must be a PhysicsFrame constructor of some kind
|
||||
append(any);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void PhysicsFrameSpline::correct(PhysicsFrame& frame) const {
|
||||
frame.rotation.unitize();
|
||||
}
|
||||
|
||||
|
||||
void PhysicsFrameSpline::ensureShortestPath(PhysicsFrame* A, int N) const {
|
||||
for (int i = 1; i < N; ++i) {
|
||||
const Quat& p = A[i - 1].rotation;
|
||||
Quat& q = A[i].rotation;
|
||||
|
||||
float cosphi = p.dot(q);
|
||||
|
||||
if (cosphi < 0) {
|
||||
// Going the long way, so change the order
|
||||
q = -q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Plane.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file PrecomputedRandom.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Quat.cpp
|
||||
|
||||
Quaternion implementation based on Watt & Watt page 363
|
||||
|
|
@ -6,10 +6,12 @@
|
|||
@author Morgan McGuire, graphics3d.com
|
||||
|
||||
@created 2002-01-23
|
||||
@edited 2006-01-31
|
||||
@edited 2010-03-31
|
||||
*/
|
||||
|
||||
#include "G3D/Quat.h"
|
||||
#include "G3D/Any.h"
|
||||
#include "G3D/stringutils.h"
|
||||
#include "G3D/BinaryInput.h"
|
||||
#include "G3D/BinaryOutput.h"
|
||||
|
||||
|
|
@ -28,8 +30,22 @@ Quat Quat::fromAxisAngleRotation(
|
|||
}
|
||||
|
||||
|
||||
Quat::Quat(
|
||||
const Matrix3& rot) {
|
||||
Quat::Quat(const class Any& a) {
|
||||
*this = Quat();
|
||||
if (beginsWith(toLower(a.name()), "matrix3")) {
|
||||
*this = a;
|
||||
} else {
|
||||
a.verifyName("Quat");
|
||||
a.verifyType(Any::ARRAY);
|
||||
x = a[0];
|
||||
y = a[1];
|
||||
z = a[2];
|
||||
w = a[3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Quat::Quat(const Matrix3& rot) {
|
||||
|
||||
static const int plus1mod3[] = {1, 2, 0};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Random.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Ray.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Rect2D.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file ReferenceCount.cpp
|
||||
|
||||
Reference Counting Garbage Collector for C++
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file RegistryUtil.cpp
|
||||
|
||||
@created 2006-04-06
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Sphere.cpp
|
||||
|
||||
Sphere class
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Stopwatch.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "G3D/Table.h"
|
||||
#include "G3D/GMutex.h"
|
||||
#include "G3D/units.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
#include <time.h>
|
||||
|
||||
#include <cstring>
|
||||
|
|
@ -80,9 +81,9 @@
|
|||
#endif
|
||||
|
||||
// SIMM include
|
||||
#ifdef __SSE__
|
||||
#ifdef __SSE__ /* G3DFIX: Only Intel Vector Extension enabled */
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
#endif /* G3DFIX: Only Intel Vector Extension enabled */
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
|
@ -340,40 +341,6 @@ void getG3DVersion(std::string& s) {
|
|||
s = cstr;
|
||||
}
|
||||
|
||||
#if 0 // TODO: delete
|
||||
struct Directory {
|
||||
std::string path;
|
||||
Array<std::string> contents;
|
||||
};
|
||||
|
||||
static bool maybeAddDirectory(const std::string& newPath, Array<Directory>& directoryArray, bool recurse = true) {
|
||||
if (fileExists(newPath)) {
|
||||
Directory& d = directoryArray.next();
|
||||
d.path = newPath;
|
||||
getFiles(pathConcat(newPath, "*"), d.contents);
|
||||
Array<std::string> dirs;
|
||||
getDirs(pathConcat(newPath, "*"), dirs);
|
||||
d.contents.append(dirs);
|
||||
|
||||
if (recurse) {
|
||||
// Look for subdirectories
|
||||
static const std::string subdirs[] =
|
||||
{"font", "gui", "SuperShader", "cubemap", "icon", "material", "image", "md2", "md3", "ifs", "3ds", "sky", ""};
|
||||
|
||||
for (int j = 0; j < dirs.size(); ++j) {
|
||||
for (int i = 0; ! subdirs[i].empty(); ++i) {
|
||||
if (dirs[j] == subdirs[i]) {
|
||||
maybeAddDirectory(pathConcat(newPath, dirs[j]), directoryArray, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string System::findDataFile
|
||||
(const std::string& full,
|
||||
|
|
@ -385,14 +352,14 @@ std::string System::findDataFile
|
|||
|
||||
// First check if the file exists as requested. This will go
|
||||
// through the FileSystemCache, so most calls do not touch disk.
|
||||
if (fileExists(full)) {
|
||||
if (FileSystem::exists(full)) {
|
||||
return full;
|
||||
}
|
||||
|
||||
// Now check where we previously found this file.
|
||||
std::string* last = lastFound.getPointer(full);
|
||||
if (last != NULL) {
|
||||
if (fileExists(*last)) {
|
||||
if (FileSystem::exists(*last)) {
|
||||
// Even if cwd has changed the file is still present.
|
||||
// We won't notice if it has been deleted, however.
|
||||
return *last;
|
||||
|
|
@ -405,20 +372,33 @@ std::string System::findDataFile
|
|||
// Places to look
|
||||
static Array<std::string> directoryArray;
|
||||
|
||||
std::string initialAppDataDir(instance().m_appDataDir);
|
||||
const char* g3dPath = getenv("G3DDATA");
|
||||
|
||||
if (directoryArray.size() == 0) {
|
||||
// Initialize the directory array
|
||||
RealTime t0 = System::time();
|
||||
|
||||
Array<std::string> baseDirArray;
|
||||
|
||||
std::string initialAppDataDir(instance().m_appDataDir);
|
||||
|
||||
baseDirArray.append("");
|
||||
if (! initialAppDataDir.empty()) {
|
||||
baseDirArray.append(initialAppDataDir);
|
||||
}
|
||||
|
||||
const char* g3dPath = getenv("G3DDATA");
|
||||
# ifdef G3D_WIN32
|
||||
if (g3dPath == NULL) {
|
||||
// If running the demos under visual studio from the G3D.sln file,
|
||||
// this will locate the data directory.
|
||||
const char* paths[] = {"../data-files/", "../../data-files/", "../../../data-files/", NULL};
|
||||
for (int i = 0; paths[i]; ++i) {
|
||||
if (FileSystem::exists(pathConcat(paths[i], "G3D-DATA-README.TXT"))) {
|
||||
g3dPath = paths[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
if (g3dPath && (initialAppDataDir != g3dPath)) {
|
||||
baseDirArray.append(g3dPath);
|
||||
|
|
@ -428,11 +408,11 @@ std::string System::findDataFile
|
|||
{"font", "gui", "SuperShader", "cubemap", "icon", "material", "image", "md2", "md3", "ifs", "3ds", "sky", ""};
|
||||
for (int j = 0; j < baseDirArray.size(); ++j) {
|
||||
std::string d = baseDirArray[j];
|
||||
if (fileExists(d)) {
|
||||
if ((d == "") || FileSystem::exists(d)) {
|
||||
directoryArray.append(d);
|
||||
for (int i = 0; ! subdirs[i].empty(); ++i) {
|
||||
const std::string& p = pathConcat(d, subdirs[i]);
|
||||
if (fileExists(p)) {
|
||||
if (FileSystem::exists(p)) {
|
||||
directoryArray.append(p);
|
||||
}
|
||||
}
|
||||
|
|
@ -444,7 +424,7 @@ std::string System::findDataFile
|
|||
|
||||
for (int i = 0; i < directoryArray.size(); ++i) {
|
||||
const std::string& p = pathConcat(directoryArray[i], full);
|
||||
if (fileExists(p)) {
|
||||
if (FileSystem::exists(p)) {
|
||||
lastFound.set(full, p);
|
||||
return p;
|
||||
}
|
||||
|
|
@ -454,9 +434,29 @@ std::string System::findDataFile
|
|||
// Generate an error message
|
||||
std::string locations;
|
||||
for (int i = 0; i < directoryArray.size(); ++i) {
|
||||
locations += pathConcat(directoryArray[i], full) + "\n";
|
||||
locations += "\'" + pathConcat(directoryArray[i], full) + "'\n";
|
||||
}
|
||||
alwaysAssertM(false, "Could not find '" + full + "' in:\n" + locations);
|
||||
|
||||
std::string msg = "Could not find '" + full + "'.\n\n";
|
||||
msg += "cwd = \'" + FileSystem::currentDirectory() + "\'\n";
|
||||
if (g3dPath) {
|
||||
msg += "G3DDATA = ";
|
||||
if (! FileSystem::exists(g3dPath)) {
|
||||
msg += "(illegal path!) ";
|
||||
}
|
||||
msg += std::string(g3dPath) + "\'\n";
|
||||
} else {
|
||||
msg += "(G3DDATA environment variable is undefined)\n";
|
||||
}
|
||||
msg += "GApp::Settings.dataDir = ";
|
||||
if (! FileSystem::exists(initialAppDataDir)) {
|
||||
msg += "(illegal path!) ";
|
||||
}
|
||||
msg += std::string(initialAppDataDir) + "\'\n";
|
||||
|
||||
msg += "\nLocations searched:\n" + locations;
|
||||
|
||||
alwaysAssertM(false, msg);
|
||||
}
|
||||
|
||||
// Not found
|
||||
|
|
@ -474,19 +474,23 @@ std::string demoFindData(bool errorIfNotFound) {
|
|||
if (g3dPath) {
|
||||
return g3dPath;
|
||||
# ifdef G3D_WIN32
|
||||
} else if (fileExists("../data")) {
|
||||
} else if (FileSystem::exists("../data")) {
|
||||
// G3D install on Windows
|
||||
return "../data";
|
||||
} else if (fileExists("../data-files")) {
|
||||
} else if (FileSystem::exists("../data-files")) {
|
||||
// G3D source on Windows
|
||||
return "../data-files";
|
||||
} else if (FileSystem::exists("c:/libraries/G3D/data")) {
|
||||
return "c:/libraries/G3D/data";
|
||||
# else
|
||||
} else if (fileExists("../../../../data")) {
|
||||
} else if (FileSystem::exists("../../../../data")) {
|
||||
// G3D install on Unix
|
||||
return "../../../../data";
|
||||
} else if (fileExists("../../../../data-files")) {
|
||||
} else if (FileSystem::exists("../../../../data-files")) {
|
||||
// G3D source on Unix
|
||||
return "../../../../data-files";
|
||||
} else if (FileSystem::exists("/usr/local/G3D/data")) {
|
||||
return "/usr/local/G3D/data";
|
||||
# endif
|
||||
} else {
|
||||
return "";
|
||||
|
|
@ -560,7 +564,7 @@ void System::getStandardProcessorExtensions() {
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(G3D_WIN32) && !defined(G3D_64BIT)
|
||||
#if defined(G3D_WIN32) && !defined(G3D_64BIT) /* G3DFIX: Don't check if on 64-bit Windows platforms */
|
||||
#pragma message("Port System::memcpy SIMD to all platforms")
|
||||
/** Michael Herf's fast memcpy */
|
||||
void memcpyMMX(void* dst, const void* src, int nbytes) {
|
||||
|
|
@ -611,7 +615,7 @@ void memcpyMMX(void* dst, const void* src, int nbytes) {
|
|||
#endif
|
||||
|
||||
void System::memcpy(void* dst, const void* src, size_t numBytes) {
|
||||
#if defined(G3D_WIN32) && !defined(G3D_64BIT)
|
||||
#if defined(G3D_WIN32) && !defined(G3D_64BIT) /* G3DFIX: Don't check if on 64-bit Windows platforms */
|
||||
memcpyMMX(dst, src, numBytes);
|
||||
#else
|
||||
::memcpy(dst, src, numBytes);
|
||||
|
|
@ -621,7 +625,7 @@ void System::memcpy(void* dst, const void* src, size_t numBytes) {
|
|||
|
||||
/** Michael Herf's fastest memset. n32 must be filled with the same
|
||||
character repeated. */
|
||||
#if defined(G3D_WIN32) && !defined(G3D_64BIT)
|
||||
#if defined(G3D_WIN32) && !defined(G3D_64BIT) /* G3DFIX: Don't check if on 64-bit Windows platforms */
|
||||
#pragma message("Port System::memfill SIMD to all platforms")
|
||||
|
||||
// On x86 processors, use MMX
|
||||
|
|
@ -660,7 +664,7 @@ void memfill(void *dst, int n32, unsigned long i) {
|
|||
|
||||
|
||||
void System::memset(void* dst, uint8 value, size_t numBytes) {
|
||||
#if defined(G3D_WIN32) && !defined(G3D_64BIT)
|
||||
#if defined(G3D_WIN32) && !defined(G3D_64BIT) /* G3DFIX: Don't check if on 64-bit Windows platforms */
|
||||
uint32 v = value;
|
||||
v = v + (v << 8) + (v << 16) + (v << 24);
|
||||
G3D::memfill(dst, v, numBytes);
|
||||
|
|
@ -916,9 +920,12 @@ RealTime System::time() {
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#define REALPTR_TO_USERPTR(x) ((uint8*)(x) + sizeof (void *))
|
||||
#define USERPTR_TO_REALPTR(x) ((uint8*)(x) - sizeof (void *))
|
||||
#define REALBLOCK_SIZE(x) ((x) + sizeof (void *))
|
||||
|
||||
#define REALPTR_TO_USERPTR(x) ((uint8*)(x) + sizeof(uint32))
|
||||
#define USERPTR_TO_REALPTR(x) ((uint8*)(x) - sizeof(uint32))
|
||||
#define USERSIZE_TO_REALSIZE(x) ((x) + sizeof(uint32))
|
||||
#define REALSIZE_FROM_USERPTR(u) (*(uint32*)USERPTR_TO_REALPTR(ptr) + sizeof(uint32))
|
||||
#define USERSIZE_FROM_USERPTR(u) (*(uint32*)USERPTR_TO_REALPTR(ptr))
|
||||
|
||||
class BufferPool {
|
||||
public:
|
||||
|
|
@ -943,13 +950,19 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
/** Pointer given to the program. Unless in the tiny heap, the user size of the block is stored right in front of the pointer as a uint32.*/
|
||||
typedef void* UserPtr;
|
||||
|
||||
/** Actual block allocated on the heap */
|
||||
typedef void* RealPtr;
|
||||
|
||||
class MemBlock {
|
||||
public:
|
||||
void* ptr;
|
||||
size_t bytes;
|
||||
UserPtr ptr;
|
||||
size_t bytes;
|
||||
|
||||
inline MemBlock() : ptr(NULL), bytes(0) {}
|
||||
inline MemBlock(void* p, size_t b) : ptr(p), bytes(b) {}
|
||||
inline MemBlock(UserPtr p, size_t b) : ptr(p), bytes(b) {}
|
||||
};
|
||||
|
||||
MemBlock smallPool[maxSmallBuffers];
|
||||
|
|
@ -1006,13 +1019,13 @@ private:
|
|||
/**
|
||||
Malloc out of the tiny heap. Returns NULL if allocation failed.
|
||||
*/
|
||||
inline void* tinyMalloc(size_t bytes) {
|
||||
inline UserPtr tinyMalloc(size_t bytes) {
|
||||
// Note that we ignore the actual byte size
|
||||
// and create a constant size block.
|
||||
(void)bytes;
|
||||
assert(tinyBufferSize >= bytes);
|
||||
|
||||
void* ptr = NULL;
|
||||
UserPtr ptr = NULL;
|
||||
|
||||
if (tinyPoolSize > 0) {
|
||||
--tinyPoolSize;
|
||||
|
|
@ -1036,20 +1049,20 @@ private:
|
|||
}
|
||||
|
||||
/** Returns true if this is a pointer into the tiny heap. */
|
||||
bool inTinyHeap(void* ptr) {
|
||||
bool inTinyHeap(UserPtr ptr) {
|
||||
return
|
||||
(ptr >= tinyHeap) &&
|
||||
(ptr < (uint8*)tinyHeap + maxTinyBuffers * tinyBufferSize);
|
||||
}
|
||||
|
||||
void tinyFree(void* ptr) {
|
||||
void tinyFree(UserPtr ptr) {
|
||||
assert(ptr);
|
||||
assert(tinyPoolSize < maxTinyBuffers);
|
||||
// "Tried to free a tiny pool buffer when the tiny pool freelist is full.");
|
||||
|
||||
# ifdef G3D_DEBUG
|
||||
if (tinyPoolSize > 0) {
|
||||
void* prevOnHeap = tinyPool[tinyPoolSize - 1];
|
||||
UserPtr prevOnHeap = tinyPool[tinyPoolSize - 1];
|
||||
assert(prevOnHeap != ptr);
|
||||
// "System::malloc heap corruption detected: "
|
||||
// "the last two pointers on the freelist are identical (during tinyFree).");
|
||||
|
|
@ -1066,7 +1079,8 @@ private:
|
|||
|
||||
void flushPool(MemBlock* pool, int& poolSize) {
|
||||
for (int i = 0; i < poolSize; ++i) {
|
||||
::free(pool[i].ptr);
|
||||
bytesAllocated -= USERSIZE_TO_REALSIZE(pool[i].bytes);
|
||||
::free(USERPTR_TO_REALPTR(pool[i].ptr));
|
||||
pool[i].ptr = NULL;
|
||||
pool[i].bytes = 0;
|
||||
}
|
||||
|
|
@ -1074,24 +1088,23 @@ private:
|
|||
}
|
||||
|
||||
|
||||
/** Allocate out of a specific pool-> Return NULL if no suitable
|
||||
memory was found.
|
||||
|
||||
*/
|
||||
void* malloc(MemBlock* pool, int& poolSize, size_t bytes) {
|
||||
/** Allocate out of a specific pool. Return NULL if no suitable
|
||||
memory was found. */
|
||||
UserPtr malloc(MemBlock* pool, int& poolSize, size_t bytes) {
|
||||
|
||||
// OPT: find the smallest block that satisfies the request.
|
||||
|
||||
// See if there's something we can use in the buffer pool->
|
||||
// See if there's something we can use in the buffer pool.
|
||||
// Search backwards since usually we'll re-use the last one.
|
||||
for (int i = (int)poolSize - 1; i >= 0; --i) {
|
||||
if (pool[i].bytes >= bytes) {
|
||||
// We found a suitable entry in the pool->
|
||||
// We found a suitable entry in the pool.
|
||||
|
||||
// No need to offset the pointer; it is already offset
|
||||
void* ptr = pool[i].ptr;
|
||||
UserPtr ptr = pool[i].ptr;
|
||||
|
||||
// Remove this element from the pool
|
||||
// Remove this element from the pool, replacing it with
|
||||
// the one from the end (same as Array::fastRemove)
|
||||
--poolSize;
|
||||
pool[i] = pool[poolSize];
|
||||
|
||||
|
|
@ -1155,6 +1168,8 @@ public:
|
|||
|
||||
~BufferPool() {
|
||||
::free(tinyHeap);
|
||||
flushPool(smallPool, smallPoolSize);
|
||||
flushPool(medPool, medPoolSize);
|
||||
#if 0 //-------------------------------- old mutex
|
||||
# ifdef G3D_WIN32
|
||||
DeleteCriticalSection(&mutex);
|
||||
|
|
@ -1165,7 +1180,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void* realloc(void* ptr, size_t bytes) {
|
||||
UserPtr realloc(UserPtr ptr, size_t bytes) {
|
||||
if (ptr == NULL) {
|
||||
return malloc(bytes);
|
||||
}
|
||||
|
|
@ -1177,7 +1192,7 @@ public:
|
|||
} else {
|
||||
// Free the old pointer and malloc
|
||||
|
||||
void* newPtr = malloc(bytes);
|
||||
UserPtr newPtr = malloc(bytes);
|
||||
System::memcpy(newPtr, ptr, tinyBufferSize);
|
||||
tinyFree(ptr);
|
||||
return newPtr;
|
||||
|
|
@ -1187,28 +1202,28 @@ public:
|
|||
// In one of our heaps.
|
||||
|
||||
// See how big the block really was
|
||||
size_t realSize = *(uint32*)USERPTR_TO_REALPTR(ptr);
|
||||
if (bytes <= realSize) {
|
||||
size_t userSize = USERSIZE_FROM_USERPTR(ptr);
|
||||
if (bytes <= userSize) {
|
||||
// The old block was big enough.
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Need to reallocate
|
||||
void* newPtr = malloc(bytes);
|
||||
System::memcpy(newPtr, ptr, realSize);
|
||||
// Need to reallocate and move
|
||||
UserPtr newPtr = malloc(bytes);
|
||||
System::memcpy(newPtr, ptr, userSize);
|
||||
free(ptr);
|
||||
return newPtr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void* malloc(size_t bytes) {
|
||||
UserPtr malloc(size_t bytes) {
|
||||
lock();
|
||||
++totalMallocs;
|
||||
|
||||
if (bytes <= tinyBufferSize) {
|
||||
|
||||
void* ptr = tinyMalloc(bytes);
|
||||
UserPtr ptr = tinyMalloc(bytes);
|
||||
|
||||
if (ptr) {
|
||||
++mallocsFromTinyPool;
|
||||
|
|
@ -1222,7 +1237,7 @@ public:
|
|||
// through to a small buffer
|
||||
if (bytes <= smallBufferSize) {
|
||||
|
||||
void* ptr = malloc(smallPool, smallPoolSize, bytes);
|
||||
UserPtr ptr = malloc(smallPool, smallPoolSize, bytes);
|
||||
|
||||
if (ptr) {
|
||||
++mallocsFromSmallPool;
|
||||
|
|
@ -1235,7 +1250,7 @@ public:
|
|||
// through into a medium allocation because that would
|
||||
// waste the medium buffer's resources.
|
||||
|
||||
void* ptr = malloc(medPool, medPoolSize, bytes);
|
||||
UserPtr ptr = malloc(medPool, medPoolSize, bytes);
|
||||
|
||||
if (ptr) {
|
||||
++mallocsFromMedPool;
|
||||
|
|
@ -1245,37 +1260,37 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bytesAllocated += REALBLOCK_SIZE(bytes);
|
||||
bytesAllocated += USERSIZE_TO_REALSIZE(bytes);
|
||||
unlock();
|
||||
|
||||
// Heap allocate
|
||||
|
||||
// Allocate 4 extra bytes for our size header (unfortunate,
|
||||
// since malloc already added its own header).
|
||||
void* ptr = ::malloc(REALBLOCK_SIZE(bytes));
|
||||
RealPtr ptr = ::malloc(USERSIZE_TO_REALSIZE(bytes));
|
||||
|
||||
if (ptr == NULL) {
|
||||
// Flush memory pools to try and recover space
|
||||
flushPool(smallPool, smallPoolSize);
|
||||
flushPool(medPool, medPoolSize);
|
||||
ptr = ::malloc(REALBLOCK_SIZE(bytes));
|
||||
ptr = ::malloc(USERSIZE_TO_REALSIZE(bytes));
|
||||
}
|
||||
|
||||
if (ptr == NULL) {
|
||||
if ((System::outOfMemoryCallback() != NULL) &&
|
||||
(System::outOfMemoryCallback()(REALBLOCK_SIZE(bytes), true) == true)) {
|
||||
(System::outOfMemoryCallback()(USERSIZE_TO_REALSIZE(bytes), true) == true)) {
|
||||
// Re-attempt the malloc
|
||||
ptr = ::malloc(REALBLOCK_SIZE(bytes));
|
||||
ptr = ::malloc(USERSIZE_TO_REALSIZE(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr == NULL) {
|
||||
if (System::outOfMemoryCallback() != NULL) {
|
||||
// Notify the application
|
||||
System::outOfMemoryCallback()(REALBLOCK_SIZE(bytes), false);
|
||||
System::outOfMemoryCallback()(USERSIZE_TO_REALSIZE(bytes), false);
|
||||
}
|
||||
# ifdef G3D_DEBUG
|
||||
debugPrintf("::malloc(%d) returned NULL\n", (int)REALBLOCK_SIZE(bytes));
|
||||
debugPrintf("::malloc(%d) returned NULL\n", (int)USERSIZE_TO_REALSIZE(bytes));
|
||||
# endif
|
||||
debugAssertM(ptr != NULL,
|
||||
"::malloc returned NULL. Either the "
|
||||
|
|
@ -1290,7 +1305,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void free(void* ptr) {
|
||||
void free(UserPtr ptr) {
|
||||
if (ptr == NULL) {
|
||||
// Free does nothing on null pointers
|
||||
return;
|
||||
|
|
@ -1305,7 +1320,7 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
uint32 bytes = *(uint32*)USERPTR_TO_REALPTR(ptr);
|
||||
uint32 bytes = USERSIZE_FROM_USERPTR(ptr);
|
||||
|
||||
lock();
|
||||
if (bytes <= smallBufferSize) {
|
||||
|
|
@ -1323,7 +1338,7 @@ public:
|
|||
return;
|
||||
}
|
||||
}
|
||||
bytesAllocated -= REALBLOCK_SIZE(bytes);
|
||||
bytesAllocated -= USERSIZE_TO_REALSIZE(bytes);
|
||||
unlock();
|
||||
|
||||
// Free; the buffer pools are full or this is too big to store.
|
||||
|
|
@ -1677,7 +1692,7 @@ std::string System::currentDateString() {
|
|||
|
||||
// VC on Intel
|
||||
void System::cpuid(CPUIDFunction func, uint32& areg, uint32& breg, uint32& creg, uint32& dreg) {
|
||||
#if !defined(G3D_64BIT)
|
||||
#if !defined(G3D_64BIT) /* G3DFIX: Don't check if on 64-bit platform */
|
||||
// Can't copy from assembler direct to a function argument (which is on the stack) in VC.
|
||||
uint32 a,b,c,d;
|
||||
|
||||
|
|
@ -1695,14 +1710,14 @@ void System::cpuid(CPUIDFunction func, uint32& areg, uint32& breg, uint32& creg,
|
|||
breg = b;
|
||||
creg = c;
|
||||
dreg = d;
|
||||
#else
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, func);
|
||||
memcpy(&areg, &CPUInfo[0], 4);
|
||||
memcpy(&breg, &CPUInfo[1], 4);
|
||||
memcpy(&creg, &CPUInfo[2], 4);
|
||||
memcpy(&dreg, &CPUInfo[3], 4);
|
||||
#endif
|
||||
#else /* G3DFIX: Don't check if on 64-bit platform */
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, func);
|
||||
memcpy(&areg, &CPUInfo[0], 4);
|
||||
memcpy(&breg, &CPUInfo[1], 4);
|
||||
memcpy(&creg, &CPUInfo[2], 4);
|
||||
memcpy(&dreg, &CPUInfo[3], 4);
|
||||
#endif /* G3DFIX: Don't check if on 64-bit platform */
|
||||
}
|
||||
|
||||
#elif defined(G3D_OSX) && ! defined(G3D_OSX_INTEL)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file TextInput.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
@cite Based on a lexer written by Aaron Orenstein.
|
||||
|
||||
@created 2001-11-27
|
||||
@edited 2008-07-14
|
||||
@edited 2010-07-03
|
||||
*/
|
||||
|
||||
#include "G3D/fileutils.h"
|
||||
|
|
@ -33,37 +33,46 @@ Token TextInput::readSignificant() {
|
|||
|
||||
double Token::number() const {
|
||||
if (_type == NUMBER) {
|
||||
std::string s = toLower(_string);
|
||||
if (s == "-1.#ind00") {
|
||||
return nan();
|
||||
}
|
||||
|
||||
if (s == "1.#inf00") {
|
||||
return inf();
|
||||
}
|
||||
|
||||
if (s == "-1.#inf00") {
|
||||
return -inf();
|
||||
}
|
||||
|
||||
double n;
|
||||
if ((_string.length() > 2) &&
|
||||
(_string[0] == '0') &&
|
||||
(_string[1] == 'x')) {
|
||||
// Hex
|
||||
uint32 i;
|
||||
sscanf(_string.c_str(), "%x", &i);
|
||||
n = i;
|
||||
} else {
|
||||
sscanf(_string.c_str(), "%lg", &n);
|
||||
}
|
||||
return n;
|
||||
return TextInput::parseNumber(_string);
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TextInput::parseBoolean(const std::string& _string) {
|
||||
return toLower(_string) == "true";
|
||||
}
|
||||
|
||||
double TextInput::parseNumber(const std::string& _string) {
|
||||
std::string s = toLower(_string);
|
||||
if (s == "-1.#ind00" || s == "nan") {
|
||||
return nan();
|
||||
}
|
||||
|
||||
if (s == "1.#inf00" || s == "inf" || s == "+inf") {
|
||||
return inf();
|
||||
}
|
||||
|
||||
if (s == "-1.#inf00" || s == "-inf") {
|
||||
return -inf();
|
||||
}
|
||||
|
||||
double n;
|
||||
if ((_string.length() > 2) &&
|
||||
(_string[0] == '0') &&
|
||||
(_string[1] == 'x')) {
|
||||
// Hex
|
||||
uint32 i;
|
||||
sscanf(_string.c_str(), "%x", &i);
|
||||
n = i;
|
||||
} else {
|
||||
sscanf(_string.c_str(), "%lg", &n);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
TextInput::Settings::Settings () :
|
||||
cppBlockComments(true),
|
||||
cppLineComments(true),
|
||||
|
|
@ -78,7 +87,8 @@ TextInput::Settings::Settings () :
|
|||
singleQuoteCharacter('\''),
|
||||
sourceFileName(),
|
||||
startingLineNumberOffset(0),
|
||||
msvcSpecials(true),
|
||||
msvcFloatSpecials(true),
|
||||
simpleFloatSpecials(true),
|
||||
proofSymbols(false),
|
||||
caseSensitive(true)
|
||||
{
|
||||
|
|
@ -117,6 +127,41 @@ Token TextInput::read() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string TextInput::readUntilNewlineAsString() {
|
||||
/*
|
||||
// Reset the read position back to the start of that token
|
||||
currentCharOffset = t.bytePosition();
|
||||
lineNumber = t.line();
|
||||
charNumber = t.character();
|
||||
stack.clear();
|
||||
|
||||
if (currentCharOffset == buffer.size()) {
|
||||
// End of file
|
||||
return "";
|
||||
}
|
||||
*/
|
||||
std::string s;
|
||||
|
||||
// Read until newline or eof
|
||||
char c = '\0';
|
||||
do {
|
||||
c = buffer[currentCharOffset];
|
||||
if (c == '\r' || c == '\n') {
|
||||
// Done
|
||||
break;
|
||||
} else {
|
||||
s += c;
|
||||
++currentCharOffset;
|
||||
++charNumber;
|
||||
}
|
||||
} while (currentCharOffset < buffer.size());
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static void toUpper(Set<std::string>& set) {
|
||||
Array<std::string> symbols;
|
||||
set.getMembers(symbols);
|
||||
|
|
@ -198,6 +243,7 @@ int TextInput::peekInputChar(int distance) {
|
|||
Token TextInput::nextToken() {
|
||||
Token t;
|
||||
|
||||
t._bytePosition = currentCharOffset;
|
||||
t._line = lineNumber;
|
||||
t._character = charNumber;
|
||||
t._type = Token::END;
|
||||
|
|
@ -215,21 +261,24 @@ Token TextInput::nextToken() {
|
|||
whitespaceDone = true;
|
||||
|
||||
// generate newlines tokens for '\n' and '\r' and '\r\n'
|
||||
if (options.generateNewlineTokens && isNewline(c)) {
|
||||
t._type = Token::NEWLINE;
|
||||
t._extendedType = Token::NEWLINE_TYPE;
|
||||
t._string = c;
|
||||
while (isWhiteSpace(c)) {
|
||||
if (options.generateNewlineTokens && isNewline(c)) {
|
||||
t._type = Token::NEWLINE;
|
||||
t._extendedType = Token::NEWLINE_TYPE;
|
||||
t._bytePosition = currentCharOffset;
|
||||
t._line = lineNumber;
|
||||
t._character = charNumber;
|
||||
t._string = c;
|
||||
|
||||
int c2 = peekInputChar(1);
|
||||
if (c == '\r' && c2 == '\n') {
|
||||
t._string += c2;
|
||||
}
|
||||
int c2 = peekInputChar(1);
|
||||
if (c == '\r' && c2 == '\n') {
|
||||
t._string += c2;
|
||||
}
|
||||
|
||||
eatInputChar();
|
||||
return t;
|
||||
} else {
|
||||
// Consume whitespace
|
||||
while (isWhiteSpace(c)) {
|
||||
eatInputChar();
|
||||
return t;
|
||||
} else {
|
||||
// Consume the single whitespace
|
||||
c = eatAndPeekInputChar();
|
||||
}
|
||||
}
|
||||
|
|
@ -237,6 +286,7 @@ Token TextInput::nextToken() {
|
|||
// update line and character number to include discarded whitespace
|
||||
t._line = lineNumber;
|
||||
t._character = charNumber;
|
||||
t._bytePosition = currentCharOffset;
|
||||
|
||||
int c2 = peekInputChar(1);
|
||||
|
||||
|
|
@ -293,13 +343,16 @@ Token TextInput::nextToken() {
|
|||
eatInputChar();
|
||||
eatInputChar();
|
||||
|
||||
// c is the next character we'll read, c2 is the one after *that*
|
||||
c = peekInputChar();
|
||||
c2 = peekInputChar(1);
|
||||
while (! ((c == '*') && (c2 == '/')) && (c != EOF)) {
|
||||
commentString += c;
|
||||
|
||||
// Eat input char may consume more than one character if there is a newline
|
||||
eatInputChar();
|
||||
c = c2;
|
||||
|
||||
c = peekInputChar();
|
||||
c2 = peekInputChar(1);
|
||||
}
|
||||
eatInputChar(); // eat closing '*'
|
||||
|
|
@ -324,6 +377,7 @@ Token TextInput::nextToken() {
|
|||
|
||||
t._line = lineNumber;
|
||||
t._character = charNumber;
|
||||
t._bytePosition = currentCharOffset;
|
||||
|
||||
// handle EOF
|
||||
if (c == EOF) {
|
||||
|
|
@ -380,15 +434,29 @@ Token TextInput::nextToken() {
|
|||
return t;
|
||||
}
|
||||
|
||||
if (options.signedNumbers
|
||||
&& (isDigit(c) || (c == '.' && isDigit(peekInputChar(1))))) {
|
||||
if (options.signedNumbers) {
|
||||
if (isDigit(c) || (c == '.' && isDigit(peekInputChar(1)))) {
|
||||
// Negative number. 'c' is still the first digit, and is
|
||||
// the next input char.
|
||||
|
||||
// Negative number. 'c' is still the first digit, and is
|
||||
// the next input char.
|
||||
|
||||
goto numLabel;
|
||||
goto numLabel;
|
||||
} else {
|
||||
char terminal = peekInputChar(3);
|
||||
if (options.simpleFloatSpecials && (c == 'i') && (peekInputChar(1) == 'n') && (peekInputChar(2) == 'f') &&
|
||||
! isLetter(terminal) && (terminal != '_')) {
|
||||
// negative infinity
|
||||
t._type = Token::NUMBER;
|
||||
t._extendedType = Token::FLOATING_POINT_TYPE;
|
||||
t._string = "-inf";
|
||||
eatInputChar(); // i
|
||||
eatInputChar(); // n
|
||||
eatInputChar(); // f
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// plain -
|
||||
return t;
|
||||
|
||||
|
|
@ -403,13 +471,26 @@ Token TextInput::nextToken() {
|
|||
return t;
|
||||
}
|
||||
|
||||
if (options.signedNumbers
|
||||
&& (isDigit(c) || (c == '.' && isDigit(peekInputChar(1))))) {
|
||||
if (options.signedNumbers) {
|
||||
if (isDigit(c) || (c == '.' && isDigit(peekInputChar(1)))) {
|
||||
// Positive number. 'c' is still the first digit, and is
|
||||
// the next input char.
|
||||
|
||||
// Positive number. 'c' is still the first digit, and is
|
||||
// the next input char.
|
||||
|
||||
goto numLabel;
|
||||
goto numLabel;
|
||||
} else {
|
||||
char terminal = peekInputChar(3);
|
||||
if (options.simpleFloatSpecials && (c == 'i') && (peekInputChar(1) == 'n') && (peekInputChar(2) == 'f') &&
|
||||
! isLetter(terminal) && (terminal != '_')) {
|
||||
// positive infinity
|
||||
t._type = Token::NUMBER;
|
||||
t._extendedType = Token::FLOATING_POINT_TYPE;
|
||||
t._string = "+inf";
|
||||
eatInputChar(); // i
|
||||
eatInputChar(); // n
|
||||
eatInputChar(); // f
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
|
|
@ -596,7 +677,7 @@ numLabel:
|
|||
c = eatAndPeekInputChar();
|
||||
|
||||
// Floating point specials (msvc format only)
|
||||
if (options.msvcSpecials && (c == '#')) {
|
||||
if (options.msvcFloatSpecials && (c == '#')) {
|
||||
isSpecial = true;
|
||||
// We are reading a floating point special value
|
||||
// of the form -1.#IND00, -1.#INF00, or 1.#INF00
|
||||
|
|
@ -607,8 +688,7 @@ numLabel:
|
|||
}
|
||||
if (test != 'I') {
|
||||
throw BadMSVCSpecial
|
||||
(
|
||||
"Incorrect floating-point special (inf or nan) "
|
||||
("Incorrect floating-point special (inf or nan) "
|
||||
"format.",
|
||||
t.line(), charNumber);
|
||||
}
|
||||
|
|
@ -714,6 +794,10 @@ numLabel:
|
|||
}
|
||||
}
|
||||
|
||||
if (options.simpleFloatSpecials && ((t._string == "nan") || (t._string == "inf"))) {
|
||||
t._type = Token::NUMBER;
|
||||
t._extendedType = Token::FLOATING_POINT_TYPE;
|
||||
}
|
||||
return t;
|
||||
|
||||
} else if (c == '\"') {
|
||||
|
|
@ -1052,6 +1136,8 @@ static const char* tokenTypeToString(Token::Type t) {
|
|||
return "Token::NUMBER";
|
||||
case Token::END:
|
||||
return "Token::END";
|
||||
case Token::NEWLINE:
|
||||
return "Token::NEWLINE";
|
||||
default:
|
||||
debugAssertM(false, "Fell through switch");
|
||||
return "?";
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
/**
|
||||
/*
|
||||
@file TextOutput.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
@created 2004-06-21
|
||||
@edited 2006-08-14
|
||||
@edited 2010-03-14
|
||||
|
||||
Copyright 2000-2006, Morgan McGuire.
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/Log.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
|
|
@ -392,17 +393,17 @@ void TextOutput::vprintf(const char* formatString, va_list argPtr) {
|
|||
|
||||
void TextOutput::commit(bool flush) {
|
||||
std::string p = filenamePath(filename);
|
||||
if (! fileExists(p, false)) {
|
||||
createDirectory(p);
|
||||
if (! FileSystem::exists(p, false)) {
|
||||
FileSystem::createDirectory(p);
|
||||
}
|
||||
|
||||
FILE* f = fopen(filename.c_str(), "wb");
|
||||
FILE* f = FileSystem::fopen(filename.c_str(), "wb");
|
||||
debugAssertM(f, "Could not open \"" + filename + "\"");
|
||||
fwrite(data.getCArray(), 1, data.size(), f);
|
||||
if (flush) {
|
||||
fflush(f);
|
||||
}
|
||||
fclose(f);
|
||||
FileSystem::fclose(f);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Triangle.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file UprightFrame.cpp
|
||||
Box class
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Vector2.cpp
|
||||
|
||||
2D vector class, used for texture coordinates primarily.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Vector2int16.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Vector3.cpp
|
||||
|
||||
3D vector class
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
#include "G3D/Vector2.h"
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/Vector4int8.h"
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/Vector3int32.h"
|
||||
#include "G3D/Any.h"
|
||||
|
||||
|
|
@ -104,11 +105,7 @@ Vector3::Axis Vector3::primaryAxis() const {
|
|||
|
||||
|
||||
size_t Vector3::hashCode() const {
|
||||
unsigned int xhash = (*(int*)(void*)(&x));
|
||||
unsigned int yhash = (*(int*)(void*)(&y));
|
||||
unsigned int zhash = (*(int*)(void*)(&z));
|
||||
|
||||
return xhash + (yhash * 37) + (zhash * 101);
|
||||
return Vector4(*this, 0.0f).hashCode();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Vector3& v) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Vector3int16.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Vector3int32.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
/**
|
||||
/*
|
||||
@file Vector4.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
||||
@created 2001-07-09
|
||||
@edited 2009-11-29
|
||||
@edited 2010-07-05
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
|
@ -69,12 +69,7 @@ const Vector4& Vector4::nan() {
|
|||
|
||||
|
||||
size_t Vector4::hashCode() const {
|
||||
unsigned int xhash = (*(int*)(void*)(&x));
|
||||
unsigned int yhash = (*(int*)(void*)(&y));
|
||||
unsigned int zhash = (*(int*)(void*)(&z));
|
||||
unsigned int whash = (*(int*)(void*)(&w));
|
||||
|
||||
return xhash + (yhash * 37) + (zhash * 101) + (whash * 241);
|
||||
return HashTrait<uint128>::hashCode(*((uint128*)this));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Vector4int8.cpp
|
||||
|
||||
Homogeneous vector class.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file Welder.cpp
|
||||
|
||||
@author Morgan McGuire, Kyle Whitson, Corey Taylor
|
||||
|
|
@ -74,7 +74,7 @@ namespace G3D { namespace _internal {
|
|||
|
||||
class WeldHelper {
|
||||
private:
|
||||
/** Used by getIndex and updateTriLists */
|
||||
/** Used by getIndex and updateTriLists. Deallocating this is slow. */
|
||||
PointHashGrid<VNTi> weldGrid;
|
||||
|
||||
Array<Vector3>* outputVertexArray;
|
||||
|
|
@ -88,7 +88,7 @@ private:
|
|||
|
||||
float normalSmoothingAngle;
|
||||
|
||||
/**
|
||||
/*
|
||||
Returns the index of the vertex in
|
||||
outputVertexArray/outputNormalArray/outputTexCoordArray
|
||||
that is within the global tolerances of v,n,t. If there
|
||||
|
|
@ -136,7 +136,7 @@ private:
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Updates each indexArray to refer to vertices in the
|
||||
outputVertexArray.
|
||||
|
||||
|
|
@ -157,23 +157,25 @@ private:
|
|||
int numTriLists = indexArrayArray.size();
|
||||
int u = 0;
|
||||
for (int t = 0; t < numTriLists; ++t) {
|
||||
Array<int>& triList = *(indexArrayArray[t]);
|
||||
if (indexArrayArray[t] != NULL) {
|
||||
Array<int>& triList = *(indexArrayArray[t]);
|
||||
|
||||
// For all vertices in this list
|
||||
for (int v = 0; v < triList.size(); ++v) {
|
||||
// This vertex mapped to u in the flatVertexArray
|
||||
triList[v] = getIndex(vertexArray[u], normalArray[u], texCoordArray[u]);
|
||||
// For all vertices in this list
|
||||
for (int v = 0; v < triList.size(); ++v) {
|
||||
// This vertex mapped to u in the flatVertexArray
|
||||
triList[v] = getIndex(vertexArray[u], normalArray[u], texCoordArray[u]);
|
||||
|
||||
/*
|
||||
# ifdef G3D_DEBUG
|
||||
{
|
||||
int i = triList[v];
|
||||
Vector3 N = normalArray[i];
|
||||
debugAssertM(N.length() > 0.9f, "Produced non-unit normal");
|
||||
}
|
||||
# endif
|
||||
*/
|
||||
++u;
|
||||
/*
|
||||
# ifdef G3D_DEBUG
|
||||
{
|
||||
int i = triList[v];
|
||||
Vector3 N = normalArray[i];
|
||||
debugAssertM(N.length() > 0.9f, "Produced non-unit normal");
|
||||
}
|
||||
# endif
|
||||
*/
|
||||
++u;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -190,11 +192,13 @@ private:
|
|||
|
||||
int numTriLists = indexArrayArray.size();
|
||||
for (int t = 0; t < numTriLists; ++t) {
|
||||
const Array<int>& triList = *(indexArrayArray[t]);
|
||||
for (int v = 0; v < triList.size(); ++v) {
|
||||
int i = triList[v];
|
||||
unrolledVertexArray.append(vertexArray[i]);
|
||||
unrolledTexCoordArray.append(texCoordArray[i]);
|
||||
if (indexArrayArray[t] != NULL) {
|
||||
const Array<int>& triList = *(indexArrayArray[t]);
|
||||
for (int v = 0; v < triList.size(); ++v) {
|
||||
int i = triList[v];
|
||||
unrolledVertexArray.append(vertexArray[i]);
|
||||
unrolledTexCoordArray.append(texCoordArray[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,15 +218,16 @@ private:
|
|||
const Vector3& e1 = vertexArray[v + 2] - vertexArray[v];
|
||||
|
||||
// Note that the length may be zero in the case of sliver polygons, e.g.,
|
||||
// those correcting a T-junction.
|
||||
const Vector3& n = e0.cross(e1).directionOrZero();
|
||||
// those correcting a T-junction. Scale up by 256 to avoid underflow when
|
||||
// multiplying very small edges
|
||||
const Vector3& n = (e0.cross(e1 * 256.0f)).directionOrZero();
|
||||
|
||||
// Append the normal once per vertex.
|
||||
faceNormalArray.append(n, n, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
Computes @a smoothNormalArray, whose elements are those of normalArray averaged
|
||||
with neighbors within the angular cutoff.
|
||||
*/
|
||||
|
|
@ -230,15 +235,16 @@ private:
|
|||
const Array<Vector3>& vertexArray,
|
||||
const Array<Vector3>& normalArray,
|
||||
Array<Vector3>& smoothNormalArray) {
|
||||
|
||||
// Create an area memory manager for fast deallocation
|
||||
MemoryManager::Ref mm = AreaMemoryManager::create(iRound(sizeof(VN) * normalArray.size() * 1.5));
|
||||
|
||||
if (normalSmoothingAngle <= 0) {
|
||||
smoothNormalArray = normalArray;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create an area memory manager for fast deallocation
|
||||
MemoryManager::Ref mm = AreaMemoryManager::create(iRound(sizeof(VN) * normalArray.size() * 1.5));
|
||||
|
||||
const float cosThresholdAngle = (float)cos(normalSmoothingAngle);
|
||||
|
||||
debugAssert(vertexArray.size() == normalArray.size());
|
||||
|
|
@ -250,6 +256,7 @@ private:
|
|||
grid.insert(VN(vertexArray[v], normalArray[v]));
|
||||
}
|
||||
|
||||
// TODO: this step could be done on multiple threads
|
||||
for (int v = 0; v < normalArray.size(); ++v) {
|
||||
// Compute the sum of all nearby normals within the cutoff angle.
|
||||
// Search within the vertexWeldRadius, since those are the vertices
|
||||
|
|
@ -265,8 +272,8 @@ private:
|
|||
const float cosAngle = N.dot(original);
|
||||
|
||||
if (cosAngle > cosThresholdAngle) {
|
||||
// This normal is close enough to consider
|
||||
sum += N;
|
||||
// This normal is close enough to consider. Avoid underflow by scaling up
|
||||
sum += (N * 256.0f);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
|
@ -290,7 +297,7 @@ private:
|
|||
public:
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Algorithm:
|
||||
|
||||
1. Unroll the indexed triangle list into a triangle list, where
|
||||
|
|
@ -366,8 +373,9 @@ public:
|
|||
}
|
||||
|
||||
WeldHelper(float vertRadius) :
|
||||
weldGrid(vertRadius),
|
||||
vertexWeldRadius(vertRadius) {}
|
||||
weldGrid(vertRadius, AreaMemoryManager::create()),
|
||||
vertexWeldRadius(vertRadius) {
|
||||
}
|
||||
|
||||
};
|
||||
} // Internal
|
||||
|
|
@ -382,6 +390,7 @@ void Welder::weld(
|
|||
_internal::WeldHelper(settings.vertexWeldRadius).process(
|
||||
vertexArray, texCoordArray, normalArray, indexArrayArray,
|
||||
settings.normalSmoothingAngle, settings.textureWeldRadius, settings.normalWeldRadius);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
216
dep/src/g3dlite/XML.cpp
Normal file
216
dep/src/g3dlite/XML.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
\file XML.h
|
||||
|
||||
\author Morgan McGuire
|
||||
\maintainer Morgan McGuire
|
||||
|
||||
\created 2010-02-11
|
||||
\edited 2010-02-24
|
||||
|
||||
Copyright 2000-2010, Morgan McGuire.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "G3D/XML.h"
|
||||
#include "G3D/fileutils.h"
|
||||
#include "G3D/TextInput.h"
|
||||
#include "G3D/TextOutput.h"
|
||||
#include "G3D/stringutils.h"
|
||||
|
||||
namespace G3D {
|
||||
|
||||
XML::XML(TextInput& t) : m_type(VALUE) {
|
||||
deserialize(t);
|
||||
}
|
||||
|
||||
double XML::number() const {
|
||||
return TextInput::parseNumber(m_value);
|
||||
}
|
||||
|
||||
|
||||
bool XML::boolean() const {
|
||||
return TextInput::parseBoolean(m_value);
|
||||
}
|
||||
|
||||
|
||||
void XML::load(const std::string& filename) {
|
||||
TextInput::Settings s;
|
||||
s.cppBlockComments = false;
|
||||
s.cppLineComments = false;
|
||||
s.proofSymbols = false;
|
||||
|
||||
TextInput t(filename, s);
|
||||
deserialize(t);
|
||||
}
|
||||
|
||||
|
||||
void XML::save(const std::string& filename) const {
|
||||
std::string s;
|
||||
unparse(s);
|
||||
writeWholeFile(filename, s);
|
||||
}
|
||||
|
||||
|
||||
void XML::unparse(std::string &s) const {
|
||||
TextOutput::Settings set;
|
||||
set.wordWrap = TextOutput::Settings::WRAP_WITHOUT_BREAKING;
|
||||
TextOutput t(set);
|
||||
|
||||
serialize(t);
|
||||
|
||||
t.commitString(s);
|
||||
}
|
||||
|
||||
|
||||
void XML::serialize(TextOutput& t) const {
|
||||
if (m_type == VALUE) {
|
||||
// Raw string; no quotes
|
||||
t.writeSymbol(m_value);
|
||||
} else {
|
||||
t.printf("<%s", m_name.c_str());
|
||||
for (AttributeTable::Iterator it = m_attribute.begin(); it.hasMore(); ++it) {
|
||||
t.printf(" %s=\"%s\"", it->key.c_str(), it->value.m_value.c_str());
|
||||
}
|
||||
t.printf(">");
|
||||
t.writeNewline();
|
||||
t.pushIndent();
|
||||
for (int i = 0; i < m_child.size(); ++i) {
|
||||
m_child[i].serialize(t);
|
||||
if (m_child[i].m_type == VALUE) {
|
||||
// Only tags know to append a newline
|
||||
t.writeNewline();
|
||||
}
|
||||
}
|
||||
t.popIndent();
|
||||
t.printf("</%s>", m_name.c_str());
|
||||
t.writeNewline();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void XML::parse(const std::string& s) {
|
||||
TextInput t(TextInput::FROM_STRING, s);
|
||||
deserialize(t);
|
||||
}
|
||||
|
||||
|
||||
/** True if the next token begins the close tag */
|
||||
static bool atClose(TextInput& t, const std::string name) {
|
||||
if ((t.peek().type() == Token::SYMBOL) && (t.peek().string() == "<")) {
|
||||
// Need to keep looking ahead
|
||||
Token p0 = t.read();
|
||||
if ((t.peek().type() == Token::SYMBOL) && (t.peek().string() == "/")) {
|
||||
// Check the name on the close tag. It *must* match if
|
||||
// this is a well-formed document, but there might be a
|
||||
// tag error.
|
||||
Token p1 = t.read();
|
||||
Token p2 = t.peek();
|
||||
std::string s = p2.string();
|
||||
debugAssertM(beginsWith(name, s), "Mismatched close tag");
|
||||
|
||||
// Put the tokens back
|
||||
t.push(p1);
|
||||
t.push(p0);
|
||||
return true;
|
||||
} else {
|
||||
// Put the read token back
|
||||
t.push(p0);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void XML::deserialize(TextInput& t) {
|
||||
begin:
|
||||
Token n = t.read();
|
||||
m_attribute.clear();
|
||||
m_child.clear();
|
||||
m_name = "";
|
||||
m_value = "";
|
||||
|
||||
if ((n.type() == Token::SYMBOL) && (n.string() == "<")) {
|
||||
// Beginning a tag
|
||||
|
||||
// Read name
|
||||
n = t.read();
|
||||
debugAssert(n.type() == Token::SYMBOL);
|
||||
bool isComment =
|
||||
(n.string() == "!") &&
|
||||
(t.peek().type() == Token::SYMBOL) &&
|
||||
(t.peek().string() == "--");
|
||||
|
||||
// ignored tag: <?xml> or <!xml>
|
||||
// comment tag: <!-- ... -->
|
||||
|
||||
if ((n.string() == "?") || ((n.string() == "!") && ! isComment)) {
|
||||
// Ignore this tag
|
||||
while (t.hasMore() && ! ((n.type() == Token::SYMBOL) && (n.string() == ">"))) {
|
||||
n = t.read();
|
||||
}
|
||||
goto begin;
|
||||
} else if (isComment) {
|
||||
// Ignore until "-->"
|
||||
bool prevWasDash = false;
|
||||
while (t.hasMore() && ! ((n.type() == Token::SYMBOL) && (n.string() == ">") && prevWasDash)) {
|
||||
prevWasDash = (n.type() == Token::SYMBOL) && (n.string() == "--");
|
||||
n = t.read();
|
||||
}
|
||||
goto begin;
|
||||
}
|
||||
|
||||
// Keep reading until no colon
|
||||
m_name += n.string();
|
||||
n = t.read();
|
||||
while ((n.type() == Token::SYMBOL) && (n.string() == ":")) {
|
||||
// tag with namespace: <x:y>
|
||||
m_name += ":" + t.readSymbol();
|
||||
n = t.read();
|
||||
}
|
||||
|
||||
// Read end of tag/close
|
||||
bool done = false;
|
||||
while (! done) {
|
||||
debugAssert(n.type() == Token::SYMBOL);
|
||||
if (n.string() == "/") {
|
||||
// empty-element tag: <foo/>
|
||||
// Consume the close tag
|
||||
t.readSymbol(">");
|
||||
done = true;
|
||||
|
||||
} else if (n.string() == ">") {
|
||||
// End of open tag: read children until close tag
|
||||
while (! atClose(t, m_name)) {
|
||||
m_child.next().deserialize(t);
|
||||
}
|
||||
|
||||
// Read close tag (we wouldn't be here unless it parses correctly)
|
||||
while (t.hasMore() && ! (t.readSymbol() == ">")) {}
|
||||
|
||||
done = true;
|
||||
} else {
|
||||
// Attribute pair
|
||||
std::string k = n.string();
|
||||
t.readSymbol("=");
|
||||
std::string v = t.read().string();
|
||||
m_attribute.set(k, v);
|
||||
|
||||
// Advance to next
|
||||
n = t.read();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Beginning embedded content. Read until the end of file or the next tag.
|
||||
m_type = VALUE;
|
||||
m_value += n.string();
|
||||
|
||||
n = t.peek();
|
||||
while (t.hasMore() && ! ((n.type() == Token::SYMBOL) && (n.string() == "<"))) {
|
||||
m_value += " " + t.read().string();
|
||||
n = t.peek();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file constants.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
@ -11,72 +11,6 @@
|
|||
|
||||
namespace G3D {
|
||||
|
||||
const std::string MirrorQuality::str[] = {"NONE", "STATIC_ENV", "DYNAMIC_PLANAR", "DYNAMIC_ENV", "BEST"};
|
||||
const MirrorQuality::Value MirrorQuality::enm[] = {MirrorQuality::NONE, MirrorQuality::STATIC_ENV,
|
||||
MirrorQuality::DYNAMIC_PLANAR, MirrorQuality::DYNAMIC_ENV, MirrorQuality::BEST};
|
||||
|
||||
MirrorQuality::MirrorQuality(const class Any& any) {
|
||||
*this = any;
|
||||
}
|
||||
|
||||
|
||||
MirrorQuality& MirrorQuality::operator=(const Any& any) {
|
||||
const std::string& s = toUpper(any.string());
|
||||
|
||||
for (int i = 0; ! str[i].empty(); ++i) {
|
||||
if (s == str[i]) {
|
||||
value = enm[i];
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
any.verify(false, "Unrecognized MirrorQuality constant");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
MirrorQuality::operator Any() const {
|
||||
return toString();
|
||||
}
|
||||
|
||||
|
||||
const std::string& MirrorQuality::toString() const {
|
||||
return str[value];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const std::string RefractionQuality::str[] = {"NONE", "STATIC_ENV", "DYNAMIC_FLAT", "DYNAMIC_FLAT_MULTILAYER", "DYNAMIC_ENV", "BEST"};
|
||||
const RefractionQuality::Value RefractionQuality::enm[] = {RefractionQuality::NONE, RefractionQuality::STATIC_ENV,
|
||||
RefractionQuality::DYNAMIC_FLAT, RefractionQuality::DYNAMIC_FLAT_MULTILAYER, RefractionQuality::DYNAMIC_ENV, RefractionQuality::BEST};
|
||||
|
||||
RefractionQuality::RefractionQuality(const class Any& any) {
|
||||
*this = any;
|
||||
}
|
||||
|
||||
|
||||
RefractionQuality& RefractionQuality::operator=(const Any& any) {
|
||||
const std::string& s = toUpper(any.string());
|
||||
|
||||
for (int i = 0; ! str[i].empty(); ++i) {
|
||||
if (s == str[i]) {
|
||||
value = enm[i];
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
any.verify(false, "Unrecognized RefractionQuality constant");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
RefractionQuality::operator Any() const {
|
||||
return toString();
|
||||
}
|
||||
|
||||
|
||||
const std::string& RefractionQuality::toString() const {
|
||||
return str[value];
|
||||
}
|
||||
|
||||
} // G3D
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file debugAssert.cpp
|
||||
|
||||
Windows implementation of assertion routines.
|
||||
|
|
@ -37,10 +37,10 @@ AssertionHook _debugHook = _handleDebugAssert_;
|
|||
AssertionHook _failureHook = _handleErrorCheck_;
|
||||
|
||||
#ifdef G3D_LINUX
|
||||
#if SOMEONE_MADE_THIS_USEFUL
|
||||
#if SOMEONE_MADE_THIS_USEFUL /* G3DFIX: Disabled to avoid requirement for X11 libraries */
|
||||
Display* x11Display = NULL;
|
||||
Window x11Window = 0;
|
||||
#endif
|
||||
#endif /* G3DFIX: Disabled to avoid requirement for X11 libraries */
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ static void postToClipboard(const char *text) {
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
/*
|
||||
outTitle should be set before the call
|
||||
*/
|
||||
static void createErrorMessage(
|
||||
|
|
@ -252,7 +252,7 @@ void _releaseInputGrab_() {
|
|||
ClipCursor(NULL);
|
||||
|
||||
#elif defined(G3D_LINUX)
|
||||
#if SOMEONE_MADE_THIS_USEFUL
|
||||
#if SOMEONE_MADE_THIS_USEFUL /* G3DFIX: Disabled to avoid requirement for X11 libraries */
|
||||
if (x11Display != NULL) {
|
||||
XUngrabPointer(x11Display, CurrentTime);
|
||||
XUngrabKeyboard(x11Display, CurrentTime);
|
||||
|
|
@ -267,7 +267,7 @@ void _releaseInputGrab_() {
|
|||
XAllowEvents(x11Display, AsyncPointer, CurrentTime);
|
||||
XFlush(x11Display);
|
||||
}
|
||||
#endif
|
||||
#endif /* G3DFIX: Disabled to avoid requirement for X11 libraries */
|
||||
#elif defined(G3D_OSX)
|
||||
// TODO: OS X
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file fileutils.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
|
@ -17,12 +17,13 @@
|
|||
#include "G3D/stringutils.h"
|
||||
#include "G3D/Set.h"
|
||||
#include "G3D/g3dfnmatch.h"
|
||||
#include "G3D/FileSystem.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#if _HAVE_ZIP
|
||||
#include "zip.h"
|
||||
#endif
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
#include "zip.h"
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
// Needed for _getcwd
|
||||
|
|
@ -104,17 +105,18 @@ std::string readWholeFile(
|
|||
std::string s;
|
||||
|
||||
debugAssert(filename != "");
|
||||
if (fileExists(filename, false)) {
|
||||
debugAssertM(FileSystem::exists(filename), filename + " not found");
|
||||
|
||||
int64 length = fileLength(filename);
|
||||
if (! FileSystem::inZipfile(filename)) {
|
||||
int64 length = FileSystem::size(filename);
|
||||
|
||||
char* buffer = (char*)System::alignedMalloc(length + 1, 16);
|
||||
debugAssert(buffer);
|
||||
FILE* f = fopen(filename.c_str(), "rb");
|
||||
FILE* f = FileSystem::fopen(filename.c_str(), "rb");
|
||||
debugAssert(f);
|
||||
int ret = fread(buffer, 1, length, f);
|
||||
debugAssert(ret == length);(void)ret;
|
||||
fclose(f);
|
||||
FileSystem::fclose(f);
|
||||
|
||||
buffer[length] = '\0';
|
||||
s = std::string(buffer);
|
||||
|
|
@ -134,8 +136,6 @@ std::string readWholeFile(
|
|||
buffer[length] = '\0';
|
||||
s = std::string(buffer);
|
||||
System::alignedFree(buffer);
|
||||
} else {
|
||||
debugAssertM(false, filename + " not found");
|
||||
}
|
||||
|
||||
return s;
|
||||
|
|
@ -146,7 +146,8 @@ void zipRead(const std::string& file,
|
|||
void*& data,
|
||||
size_t& length) {
|
||||
std::string zip, desiredFile;
|
||||
#if _HAVE_ZIP
|
||||
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
if (zipfileExists(file, zip, desiredFile)) {
|
||||
struct zip *z = zip_open( zip.c_str(), ZIP_CHECKCONS, NULL );
|
||||
{
|
||||
|
|
@ -169,9 +170,9 @@ void zipRead(const std::string& file,
|
|||
} else {
|
||||
data = NULL;
|
||||
}
|
||||
#else
|
||||
data = NULL;
|
||||
#endif
|
||||
#else /* G3DFIX: Use ZIP-library only if defined */
|
||||
data = NULL;
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -185,7 +186,7 @@ int64 fileLength(const std::string& filename) {
|
|||
int result = _stat(filename.c_str(), &st);
|
||||
|
||||
if (result == -1) {
|
||||
#if _HAVE_ZIP
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
std::string zip, contents;
|
||||
if(zipfileExists(filename, zip, contents)){
|
||||
int64 requiredMem;
|
||||
|
|
@ -196,6 +197,7 @@ int64 fileLength(const std::string& filename) {
|
|||
struct zip_stat info;
|
||||
zip_stat_init( &info ); // TODO: Docs unclear if zip_stat_init is required.
|
||||
int success = zip_stat( z, contents.c_str(), ZIP_FL_NOCASE, &info );
|
||||
(void)success;
|
||||
debugAssertM(success == 0, zip + ": " + contents + ": zip stat failed.");
|
||||
requiredMem = info.size;
|
||||
}
|
||||
|
|
@ -204,132 +206,14 @@ int64 fileLength(const std::string& filename) {
|
|||
} else {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
#else /* G3DFIX: Use ZIP-library only if defined */
|
||||
return -1;
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
}
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
/** Used by robustTmpfile. Returns nonzero if fread, fwrite, and fseek all
|
||||
succeed on the file.
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu */
|
||||
static int isFileGood(FILE* f) {
|
||||
|
||||
int x, n, result;
|
||||
|
||||
/* Must be a valid file handle */
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to write */
|
||||
x = 1234;
|
||||
n = fwrite(&x, sizeof(int), 1, f);
|
||||
|
||||
if (n != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Seek back to the beginning */
|
||||
result = fseek(f, 0, SEEK_SET);
|
||||
if (result != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read */
|
||||
n = fread(&x, sizeof(int), 1, f);
|
||||
if (n != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Seek back to the beginning again */
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE* createTempFile() {
|
||||
FILE* t = NULL;
|
||||
|
||||
//# ifdef G3D_WIN32
|
||||
t = tmpfile();
|
||||
//# else
|
||||
// // On Unix, tmpfile generates a warning for any code that links against it.
|
||||
// const char* tempfilename = "/tmp/g3dtemp.XXXXXXXX";
|
||||
// mktemp(tempfilename);
|
||||
// t = fopen(tempfilename, "w");
|
||||
//# endif
|
||||
|
||||
# ifdef _WIN32
|
||||
char* n = NULL;
|
||||
# endif
|
||||
char name[256];
|
||||
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
/* tmpfile failed; try the tmpnam routine */
|
||||
t = fopen(tmpnam(NULL), "w+");
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
|
||||
n = _tempnam("c:/tmp/", "t");
|
||||
/* Try to create something in C:\tmp */
|
||||
t = fopen(n, "w+");
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Try c:\temp */
|
||||
n = _tempnam("c:/temp/", "t");
|
||||
t = fopen(n, "w+");
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/* try the current directory */
|
||||
n = _tempnam("./", "t");
|
||||
t = fopen(n, "w+");
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
|
||||
sprintf(name, "%s/tmp%d", "c:/temp", rand());
|
||||
t = fopen(name, "w+");
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Try some hardcoded paths */
|
||||
sprintf(name, "%s/tmp%d", "c:/tmp", rand());
|
||||
t = fopen(name, "w+");
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
# else
|
||||
sprintf(name, "%s/tmp%d", "/tmp", rand());
|
||||
t = fopen(name, "w+");
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
#endif
|
||||
|
||||
sprintf(name, "tmp%d", rand());
|
||||
t = fopen(name, "w+");
|
||||
if (isFileGood(t)) {
|
||||
return t;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Unable to create a temporary file; robustTmpfile returning NULL\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void writeWholeFile(
|
||||
const std::string& filename,
|
||||
|
|
@ -342,11 +226,11 @@ void writeWholeFile(
|
|||
parseFilename(filename, root, pathArray, base, ext);
|
||||
|
||||
path = root + stringJoin(pathArray, '/');
|
||||
if (! fileExists(path, false)) {
|
||||
createDirectory(path);
|
||||
if (! FileSystem::exists(path, false)) {
|
||||
FileSystem::createDirectory(path);
|
||||
}
|
||||
|
||||
FILE* file = fopen(filename.c_str(), "wb");
|
||||
FILE* file = FileSystem::fopen(filename.c_str(), "wb");
|
||||
|
||||
debugAssert(file);
|
||||
|
||||
|
|
@ -355,12 +239,13 @@ void writeWholeFile(
|
|||
if (flush) {
|
||||
fflush(file);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
FileSystem::fclose(file);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
/*
|
||||
Creates the directory (which may optionally end in a /)
|
||||
and any parents needed to reach it.
|
||||
*/
|
||||
|
|
@ -385,7 +270,7 @@ void createDirectory(
|
|||
}
|
||||
|
||||
// If it already exists, do nothing
|
||||
if (fileExists(d.substr(0, d.size() - 1)), false) {
|
||||
if (FileSystem::exists(d.substr(0, d.size() - 1))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -405,129 +290,22 @@ void createDirectory(
|
|||
// Create any intermediate that doesn't exist
|
||||
for (int i = 0; i < path.size(); ++i) {
|
||||
p += "/" + path[i];
|
||||
if (! fileExists(p, false)) {
|
||||
if (! FileSystem::exists(p)) {
|
||||
// Windows only requires one argument to mkdir,
|
||||
// where as unix also requires the permissions.
|
||||
# ifndef G3D_WIN32
|
||||
mkdir(p.c_str(), 0777);
|
||||
# else
|
||||
# else
|
||||
_mkdir(p.c_str());
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FileSystemCache {
|
||||
private:
|
||||
|
||||
Table<std::string, Array<std::string> > m_files;
|
||||
|
||||
public:
|
||||
|
||||
bool fileExists(const std::string& filename) {
|
||||
const std::string& path = resolveFilename(filenamePath(filename));
|
||||
const std::string& name = filenameBaseExt(filename);
|
||||
|
||||
bool neverBeforeSeen = false;
|
||||
Array<std::string>& fileList = m_files.getCreate(path, neverBeforeSeen);
|
||||
if (neverBeforeSeen) {
|
||||
if (! G3D::fileExists(path, true, false)) {
|
||||
// The path itself doesn't exist... back out our insertion (which makes fileList& invalid)
|
||||
m_files.remove(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string spec = pathConcat(path, "*");
|
||||
|
||||
// Will automatically recurse into zipfiles
|
||||
getFiles(spec, fileList);
|
||||
getDirs(spec, fileList);
|
||||
|
||||
# ifdef G3D_WIN32
|
||||
{
|
||||
// Case insensitive
|
||||
for (int i = 0; i < fileList.size(); ++i) {
|
||||
fileList[i] = toLower(fileList[i]);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
if (filenameContainsWildcards(name)) {
|
||||
// See if anything matches
|
||||
for (int i = 0; i < fileList.size(); ++i) {
|
||||
if (g3dfnmatch(name.c_str(), fileList[i].c_str(), 0) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
// On windows, this is a lower-lower comparison, so it is case insensitive
|
||||
return fileList.contains(name);
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_files.clear();
|
||||
}
|
||||
|
||||
static FileSystemCache& instance() {
|
||||
static FileSystemCache i;
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void clearFileSystemCache() {
|
||||
FileSystemCache::instance().clear();
|
||||
}
|
||||
|
||||
bool fileExists
|
||||
(const std::string& _filename,
|
||||
bool lookInZipfiles,
|
||||
bool trustCache) {
|
||||
|
||||
if (_filename.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove trailing slash from directories
|
||||
const std::string& filename = (endsWith(_filename, "/") || endsWith(_filename, "\\")) ? _filename.substr(0, _filename.length() - 1) : _filename;
|
||||
|
||||
if (trustCache && lookInZipfiles) {
|
||||
# ifdef G3D_WIN32
|
||||
// Case insensitive
|
||||
return FileSystemCache::instance().fileExists(toLower(filename));
|
||||
# else
|
||||
return FileSystemCache::instance().fileExists(filename);
|
||||
# endif
|
||||
}
|
||||
|
||||
// Useful for debugging
|
||||
//char curdir[1024]; _getcwd(curdir, 1024);
|
||||
|
||||
struct _stat st;
|
||||
int ret = _stat(filename.c_str(), &st);
|
||||
|
||||
// _stat returns zero on success
|
||||
bool exists = (ret == 0);
|
||||
|
||||
if (! exists && lookInZipfiles) {
|
||||
// Does not exist standalone, but might exist in a zipfile
|
||||
|
||||
// These output arguments will be ignored
|
||||
std::string zipDir, internalPath;
|
||||
return zipfileExists(filename, zipDir, internalPath);
|
||||
} else {
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if _HAVE_ZIP
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
/* Helper methods for zipfileExists()*/
|
||||
// Given a string (the drive) and an array (the path), computes the directory
|
||||
static void _zip_resolveDirectory(std::string& completeDir, const std::string& drive, const Array<std::string>& path, const int length){
|
||||
|
|
@ -561,12 +339,13 @@ static bool _zip_zipContains(const std::string& zipDir, const std::string& desir
|
|||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
|
||||
// If no zipfile exists, outZipfile and outInternalFile are unchanged
|
||||
bool zipfileExists(const std::string& filename, std::string& outZipfile,
|
||||
std::string& outInternalFile){
|
||||
#if _HAVE_ZIP
|
||||
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
Array<std::string> path;
|
||||
std::string drive, base, ext, zipfile, infile;
|
||||
parseFilename(filename, drive, path, base, ext);
|
||||
|
|
@ -607,12 +386,12 @@ bool zipfileExists(const std::string& filename, std::string& outZipfile,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (fileExists(zipfile, false)) {
|
||||
if (FileSystem::exists(zipfile)) {
|
||||
// test if it actually is a zipfile
|
||||
// if not, return false, a bad
|
||||
// directory structure has been given,
|
||||
// not a .zip
|
||||
if (isZipfile(zipfile)){
|
||||
if (FileSystem::isZipfile(zipfile)){
|
||||
|
||||
if (_zip_zipContains(zipfile, infile)){
|
||||
outZipfile = zipfile;
|
||||
|
|
@ -628,7 +407,7 @@ bool zipfileExists(const std::string& filename, std::string& outZipfile,
|
|||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
// not a valid directory structure ever,
|
||||
// obviously no .zip was found within the path
|
||||
return false;
|
||||
|
|
@ -641,7 +420,7 @@ std::string generateFilenameBase(const std::string& prefix, const std::string& s
|
|||
|
||||
// Note "template" is a reserved word in C++
|
||||
std::string templat = prefix + System::currentDateString() + "_";
|
||||
getFiles(templat + "*", exist);
|
||||
FileSystem::getFiles(templat + "*", exist);
|
||||
|
||||
// Remove extensions
|
||||
for (int i = 0; i < exist.size(); ++i) {
|
||||
|
|
@ -791,7 +570,7 @@ void parseFilename(
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
Helper for getFileList and getDirectoryList.
|
||||
|
||||
@param wantFiles If false, returns the directories, otherwise
|
||||
|
|
@ -910,8 +689,9 @@ static void getFileOrDirListNormal
|
|||
# endif
|
||||
}
|
||||
|
||||
#if _HAVE_ZIP
|
||||
/**
|
||||
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
/*
|
||||
@param path The zipfile name (no trailing slash)
|
||||
@param prefix Directory inside the zipfile. No leading slash, must have trailing slash if non-empty.
|
||||
@param file Name inside the zipfile that we are testing to see if it matches prefix + "*"
|
||||
|
|
@ -961,14 +741,14 @@ static void _zip_addEntry(const std::string& path,
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
|
||||
static void getFileOrDirListZip(const std::string& path,
|
||||
const std::string& prefix,
|
||||
Array<std::string>& files,
|
||||
bool wantFiles,
|
||||
bool includePath){
|
||||
#if _HAVE_ZIP
|
||||
#if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */
|
||||
struct zip *z = zip_open( path.c_str(), ZIP_CHECKCONS, NULL );
|
||||
|
||||
Set<std::string> fileSet;
|
||||
|
|
@ -984,7 +764,7 @@ static void getFileOrDirListZip(const std::string& path,
|
|||
zip_close( z );
|
||||
|
||||
fileSet.getMembers(files);
|
||||
#endif
|
||||
#endif /* G3DFIX: Use ZIP-library only if defined */
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1004,8 +784,8 @@ static void determineFileOrDirList(
|
|||
path = path.substr(0, path.length() -1);
|
||||
}
|
||||
|
||||
if ((path == "") || fileExists(path, false)) {
|
||||
if ((path != "") && isZipfile(path)) {
|
||||
if ((path == "") || FileSystem::exists(path)) {
|
||||
if ((path != "") && FileSystem::isZipfile(path)) {
|
||||
// .zip should only work if * is specified as the Base + Ext
|
||||
// Here, we have been asked for the root's contents
|
||||
debugAssertM(filenameBaseExt(filespec) == "*", "Can only call getFiles/getDirs on zipfiles using '*' wildcard");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file filter.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file format.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
|
|
|||
|
|
@ -1,40 +1,42 @@
|
|||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
*The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
*This product includes software developed by the University of
|
||||
*California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*@(#)fnmatch.h8.1 (Berkeley) 6/2/93
|
||||
*
|
||||
* From FreeBSD fnmatch.h 1.7
|
||||
* $Id: g3dfnmatch.cpp,v 1.2 2010/02/06 10:03:24 corey_taylor Exp $
|
||||
*/
|
||||
/* $Id: g3dfnmatch.cpp,v 1.3 2010/03/15 05:01:23 morgan3d Exp $ */
|
||||
|
||||
/* $OpenBSD: fnmatch.c,v 1.7 2000/03/23 19:13:51 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Guido van Rossum.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include "G3D/g3dfnmatch.h"
|
||||
|
||||
#ifdef G3D_WIN32
|
||||
|
|
@ -45,149 +47,166 @@
|
|||
|
||||
namespace G3D {
|
||||
|
||||
#define EOS '\0'
|
||||
#define EOS '\0'
|
||||
|
||||
static const char *rangematch(const char *, char, int);
|
||||
#define RANGE_MATCH 1
|
||||
#define RANGE_NOMATCH 0
|
||||
#define RANGE_ERROR (-1)
|
||||
|
||||
int g3dfnmatch(const char *pattern, const char *string, int flags)
|
||||
static int rangematch(const char *, char, int, char **);
|
||||
|
||||
int
|
||||
g3dfnmatch(const char *pattern, const char *string, int flags)
|
||||
{
|
||||
const char *stringstart;
|
||||
char c, test;
|
||||
const char *stringstart;
|
||||
char *newp;
|
||||
char c, test;
|
||||
|
||||
for (stringstart = string;;)
|
||||
switch (c = *pattern++) {
|
||||
case EOS:
|
||||
if ((flags & FNM_LEADING_DIR) && *string == '/')
|
||||
return (0);
|
||||
return (*string == EOS ? 0 : FNM_NOMATCH);
|
||||
case '?':
|
||||
if (*string == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '/' && (flags & FNM_PATHNAME))
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
++string;
|
||||
break;
|
||||
case '*':
|
||||
c = *pattern;
|
||||
/* Collapse multiple stars. */
|
||||
while (c == '*')
|
||||
c = *++pattern;
|
||||
for (stringstart = string;;)
|
||||
switch (c = *pattern++) {
|
||||
case EOS:
|
||||
if ((flags & FNM_LEADING_DIR) && *string == '/')
|
||||
return (0);
|
||||
return (*string == EOS ? 0 : FNM_NOMATCH);
|
||||
case '?':
|
||||
if (*string == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '/' && (flags & FNM_PATHNAME))
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
++string;
|
||||
break;
|
||||
case '*':
|
||||
c = *pattern;
|
||||
/* Collapse multiple stars. */
|
||||
while (c == '*')
|
||||
c = *++pattern;
|
||||
|
||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
/* Optimize for pattern with * at end or before /. */
|
||||
if (c == EOS)
|
||||
if (flags & FNM_PATHNAME)
|
||||
return ((flags & FNM_LEADING_DIR) ||
|
||||
strchr(string, '/') == NULL ?
|
||||
0 : FNM_NOMATCH);
|
||||
else
|
||||
return (0);
|
||||
else if (c == '/' && flags & FNM_PATHNAME) {
|
||||
if ((string = strchr(string, '/')) == NULL)
|
||||
return (FNM_NOMATCH);
|
||||
break;
|
||||
}
|
||||
/* Optimize for pattern with * at end or before /. */
|
||||
if (c == EOS) {
|
||||
if (flags & FNM_PATHNAME)
|
||||
return ((flags & FNM_LEADING_DIR) ||
|
||||
strchr(string, '/') == NULL ?
|
||||
0 : FNM_NOMATCH);
|
||||
else
|
||||
return (0);
|
||||
} else if (c == '/' && (flags & FNM_PATHNAME)) {
|
||||
if ((string = strchr(string, '/')) == NULL)
|
||||
return (FNM_NOMATCH);
|
||||
break;
|
||||
}
|
||||
|
||||
/* General case, use recursion. */
|
||||
while ((test = *string) != EOS) {
|
||||
if (!rangematch(pattern, *string, flags & ~FNM_PERIOD))
|
||||
return (0);
|
||||
if (test == '/' && flags & FNM_PATHNAME)
|
||||
break;
|
||||
++string;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
case '[':
|
||||
if (*string == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '/' && flags & FNM_PATHNAME)
|
||||
return (FNM_NOMATCH);
|
||||
if ((pattern =
|
||||
rangematch(pattern, *string, flags)) == NULL)
|
||||
return (FNM_NOMATCH);
|
||||
++string;
|
||||
break;
|
||||
case '\\':
|
||||
if (!(flags & FNM_NOESCAPE)) {
|
||||
if ((c = *pattern++) == EOS) {
|
||||
c = '\\';
|
||||
--pattern;
|
||||
}
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (c == *string)
|
||||
;
|
||||
else if ((flags & FNM_CASEFOLD) &&
|
||||
(tolower((unsigned char)c) ==
|
||||
tolower((unsigned char)*string)))
|
||||
;
|
||||
else if ((flags & FNM_PREFIX_DIRS) && *string == EOS &&
|
||||
((c == '/' && string != stringstart) ||
|
||||
(string == stringstart+1 && *stringstart == '/')))
|
||||
return (0);
|
||||
else
|
||||
return (FNM_NOMATCH);
|
||||
string++;
|
||||
break;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
/* General case, use recursion. */
|
||||
while ((test = *string) != EOS) {
|
||||
if (!g3dfnmatch(pattern, string, flags & ~FNM_PERIOD))
|
||||
return (0);
|
||||
if (test == '/' && (flags & FNM_PATHNAME))
|
||||
break;
|
||||
++string;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
case '[':
|
||||
if (*string == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '/' && (flags & FNM_PATHNAME))
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '.' && (flags & FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
switch (rangematch(pattern, *string, flags, &newp)) {
|
||||
case RANGE_ERROR:
|
||||
/* not a good range, treat as normal text */
|
||||
goto normal;
|
||||
case RANGE_MATCH:
|
||||
pattern = newp;
|
||||
break;
|
||||
case RANGE_NOMATCH:
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
++string;
|
||||
break;
|
||||
case '\\':
|
||||
if (!(flags & FNM_NOESCAPE)) {
|
||||
if ((c = *pattern++) == EOS) {
|
||||
c = '\\';
|
||||
--pattern;
|
||||
}
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
normal:
|
||||
if (c != *string && !((flags & FNM_CASEFOLD) &&
|
||||
(tolower((unsigned char)c) ==
|
||||
tolower((unsigned char)*string))))
|
||||
return (FNM_NOMATCH);
|
||||
++string;
|
||||
break;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static const char *
|
||||
rangematch(const char *pattern, char test, int flags)
|
||||
static int
|
||||
rangematch(const char *pattern, char test, int flags, char **newp)
|
||||
{
|
||||
int negate, ok;
|
||||
char c, c2;
|
||||
int negate, ok;
|
||||
char c, c2;
|
||||
|
||||
/*
|
||||
* A bracket expression starting with an unquoted circumflex
|
||||
* character produces unspecified results (IEEE 1003.2-1992,
|
||||
* 3.13.2). This implementation treats it like '!', for
|
||||
* consistency with the regular expression syntax.
|
||||
* J.T. Conklin (conklin@ngai.kaleida.com)
|
||||
*/
|
||||
if ( (negate = (*pattern == '!' || *pattern == '^')) )
|
||||
++pattern;
|
||||
/*
|
||||
* A bracket expression starting with an unquoted circumflex
|
||||
* character produces unspecified results (IEEE 1003.2-1992,
|
||||
* 3.13.2). This implementation treats it like '!', for
|
||||
* consistency with the regular expression syntax.
|
||||
* J.T. Conklin (conklin@ngai.kaleida.com)
|
||||
*/
|
||||
if ((negate = (*pattern == '!' || *pattern == '^')))
|
||||
++pattern;
|
||||
|
||||
if (flags & FNM_CASEFOLD)
|
||||
test = tolower((unsigned char)test);
|
||||
if (flags & FNM_CASEFOLD)
|
||||
test = tolower((unsigned char)test);
|
||||
|
||||
for (ok = 0; (c = *pattern++) != ']';) {
|
||||
if (c == '\\' && !(flags & FNM_NOESCAPE))
|
||||
c = *pattern++;
|
||||
if (c == EOS)
|
||||
return (NULL);
|
||||
/*
|
||||
* A right bracket shall lose its special meaning and represent
|
||||
* itself in a bracket expression if it occurs first in the list.
|
||||
* -- POSIX.2 2.8.3.2
|
||||
*/
|
||||
ok = 0;
|
||||
c = *pattern++;
|
||||
do {
|
||||
if (c == '\\' && !(flags & FNM_NOESCAPE))
|
||||
c = *pattern++;
|
||||
if (c == EOS)
|
||||
return (RANGE_ERROR);
|
||||
if (c == '/' && (flags & FNM_PATHNAME))
|
||||
return (RANGE_NOMATCH);
|
||||
if ((flags & FNM_CASEFOLD))
|
||||
c = tolower((unsigned char)c);
|
||||
if (*pattern == '-'
|
||||
&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
|
||||
pattern += 2;
|
||||
if (c2 == '\\' && !(flags & FNM_NOESCAPE))
|
||||
c2 = *pattern++;
|
||||
if (c2 == EOS)
|
||||
return (RANGE_ERROR);
|
||||
if (flags & FNM_CASEFOLD)
|
||||
c2 = tolower((unsigned char)c2);
|
||||
if (c <= test && test <= c2)
|
||||
ok = 1;
|
||||
} else if (c == test)
|
||||
ok = 1;
|
||||
} while ((c = *pattern++) != ']');
|
||||
|
||||
if (flags & FNM_CASEFOLD)
|
||||
c = tolower((unsigned char)c);
|
||||
|
||||
if (*pattern == '-'
|
||||
&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
|
||||
pattern += 2;
|
||||
if (c2 == '\\' && !(flags & FNM_NOESCAPE))
|
||||
c2 = *pattern++;
|
||||
if (c2 == EOS)
|
||||
return (NULL);
|
||||
|
||||
if (flags & FNM_CASEFOLD)
|
||||
c2 = tolower((unsigned char)c2);
|
||||
|
||||
if ((unsigned char)c <= (unsigned char)test &&
|
||||
(unsigned char)test <= (unsigned char)c2)
|
||||
ok = 1;
|
||||
} else if (c == test)
|
||||
ok = 1;
|
||||
}
|
||||
return (ok == negate ? NULL : pattern);
|
||||
*newp = (char *)pattern;
|
||||
return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file g3dmath.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace G3D {
|
||||
|
||||
float gaussRandom(float mean, float stdev) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file license.cpp
|
||||
|
||||
@author Morgan McGuire, graphics3d.com
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file prompt.cpp
|
||||
|
||||
@author Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
@ -46,7 +46,7 @@ namespace G3D {
|
|||
#ifdef G3D_WIN32
|
||||
|
||||
namespace _internal {
|
||||
/**
|
||||
/*
|
||||
Generic Win32 dialog facility.
|
||||
@author Max McGuire
|
||||
*/
|
||||
|
|
@ -179,7 +179,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
*
|
||||
* Returns a pointer to the Win32 dialog template which the object
|
||||
* represents. This pointer may become invalid if additional components
|
||||
|
|
@ -295,7 +295,7 @@ struct PromptParams {
|
|||
const char* title;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Constants for controls.
|
||||
*/
|
||||
#define IDC_MESSAGE 1000
|
||||
|
|
@ -351,7 +351,7 @@ INT_PTR CALLBACK PromptDlgProc(HWND hDlg, UINT msg,
|
|||
|
||||
using namespace _internal;
|
||||
|
||||
/**
|
||||
/*
|
||||
* Show a dialog prompt.
|
||||
*/
|
||||
static int guiPrompt(
|
||||
|
|
@ -475,7 +475,7 @@ static int guiPrompt(
|
|||
#endif /* MANGOS exclude for disabled gui prompt */
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* Show a prompt on stdout
|
||||
*/
|
||||
static int textPrompt(
|
||||
|
|
@ -557,7 +557,7 @@ struct CallbackData {
|
|||
int* whichButton;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
Assumes that userData is a pointer to a carbon_evt_data_t.
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file stringutils.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/*
|
||||
@file uint128.cpp
|
||||
|
||||
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
|
||||
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
||||
#
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
|
||||
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
|
||||
#
|
||||
# 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue