Merge pull request #13 from Antidote/atdna

Added `atdna` tool to Athena
This commit is contained in:
Jack Andersen 2015-06-16 16:25:15 -10:00
commit 791a355ace
10 changed files with 676 additions and 6 deletions

View File

@ -62,7 +62,8 @@ HEADERS += \
$$PWD/include/utf8/unchecked.h \
$$PWD/include/Athena/FileInfo.hpp \
$$PWD/include/Athena/Dir.hpp \
$$PWD/include/gekko_support.h
$$PWD/include/gekko_support.h \
$$PWD/include/Athena/DNA.hpp
win32:HEADERS += \
$$PWD/include/win32_largefilewrapper.h

20
LICENSE Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2011-2015 Phillip "Antidote" Stephens, Jack Andersen, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,13 +1,13 @@
# PKGBUILD for libAthena
_pkgname=libathena
pkgname=$_pkgname-git
pkgver=v1.0.0
pkgver=1.1.0.17.gfb722a9
pkgrel=1
pkgdesc="Basic cross platform IO library"
arch=('i686' 'x86_64')
source=("${pkgname%-*}::git+https://github.com/Antidote/Athena.git")
options=(staticlibs)
license="GPL3"
license="MIT"
makedepends=('git qt5-base sed')
md5sums=('SKIP')
sha256sums=('SKIP')
@ -19,7 +19,7 @@ pkgver() {
build() {
cd "$srcdir/$_pkgname"
qmake && make
qmake PREFIX="$pkgdir/usr" && make
}
package() {

30
atdna/PKGBUILD Normal file
View File

@ -0,0 +1,30 @@
# PKGBUILD for atdna
_pkgname=atdna
pkgname=$_pkgname-git
pkgver=1.1.0.23.g647f9c4
pkgrel=1
pkgdesc="Companion DNA utility for libAthena"
arch=('i686' 'x86_64')
source=("${pkgname%-*}::git+https://github.com/Antidote/Athena.git")
options=(staticlibs)
license="MIT"
makedepends=('git qt5-base sed clang libathena-git')
depends=('libathena-git')
md5sums=('SKIP')
sha256sums=('SKIP')
pkgver() {
cd "$srcdir/$_pkgname"
git describe --tags | sed 's|-|.|g'
}
build() {
cd "$srcdir/$_pkgname/atdna"
qmake PREFIX="$pkgdir/usr" INSTALL_PREFIX="/usr" && make
}
package() {
cd "$srcdir/$_pkgname/atdna"
qmake PREFIX="$pkgdir/usr" INSTALL_PREFIX="/usr" && make install
}

60
atdna/atdna.pro Normal file
View File

@ -0,0 +1,60 @@
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
QT =
DEFINES += __STDC_LIMIT_MACROS=1 __STDC_CONSTANT_MACROS=1
QMAKE_CXXFLAGS += -fno-rtti
QMAKE_CXXFLAGS_WARN_ON = -Wno-unused-parameter
INCLUDEPATH += ../include
CONFIG(debug, debug|release) {
# FOR FULL DEBUGGING, PLEASE UNCOMMENT THESE AND POINT THEM TO
# THE INSTALL PREFIX OF YOUR OWN DEBUG BUILD OF LLVM/CLANG!!
#INCLUDEPATH += /home/jacko/llvm-build/usr/include
#LIBS += -L/home/jacko/llvm-build/usr/lib
LIBS += -g
} else {
LIBS += -flto
}
SOURCES += \
main.cpp
LIBS += -lclangFrontend -lclangTooling -lclangDriver \
-lclangSerialization -lclangParse -lclangSema \
-lclangAnalysis -lclangEdit \
-lclangAST -lclangLex -lclangBasic \
-lLLVMOption -lLLVMMCParser -lLLVMBitReader \
-lLLVMMC -lLLVMSupport -lz -lpthread -lcurses -ldl
HEADERS += \
test.hpp
unix {
isEmpty(PREFIX) {
PREFIX = /usr/local
}
isEmpty(INSTALL_PREFIX) {
INSTALL_PREFIX = /usr/local
}
utilFiles.path = $$PREFIX/bin
utilFiles.files = $$OUT_PWD/atdna
INSTALLS += utilFiles
}
win32 {
isEmpty(PREFIX) {
PREFIX = $$PWD/pkg
}
isEmpty(INSTALL_PREFIX) {
INSTALL_PREFIX = $$PWD/pkg
}
utilFiles.path = $$PREFIX/bin
utilFiles.files = $$OUT_PWD/atdna
INSTALLS += utilFiles
}
DEFINES += INSTALL_PREFIX="$$INSTALL_PREFIX"

456
atdna/main.cpp Normal file
View File

@ -0,0 +1,456 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/Version.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/CommandLine.h"
#ifndef INSTALL_PREFIX
#define INSTALL_PREFIX /usr/local
#endif
#define XSTR(s) STR(s)
#define STR(s) #s
static llvm::cl::opt<bool> Help("h", llvm::cl::desc("Alias for -help"), llvm::cl::Hidden);
static llvm::cl::OptionCategory ATDNAFormatCategory("atdna options");
static llvm::cl::opt<std::string> OutputFilename("o",
llvm::cl::desc("Specify output filename"),
llvm::cl::value_desc("filename"),
llvm::cl::Prefix);
static llvm::cl::list<std::string> InputFilenames(llvm::cl::Positional,
llvm::cl::desc("<Input files>"),
llvm::cl::OneOrMore);
class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor>
{
clang::ASTContext& context;
llvm::raw_fd_ostream& fileOut;
std::string GetOpString(const clang::Type* theType, unsigned width,
std::string fieldName, bool writerPass)
{
if (writerPass)
{
if (theType->isBuiltinType())
{
const clang::BuiltinType* bType = (clang::BuiltinType*)theType;
if (bType->isUnsignedInteger())
{
if (width == 8)
return "writer.writeUByte(" + fieldName + ");";
else if (width == 16)
return "writer.writeUint16(" + fieldName + ");";
else if (width == 32)
return "writer.writeUint32(" + fieldName + ");";
else if (width == 64)
return "writer.writeUint64(" + fieldName + ");";
}
else if (bType->isSignedInteger())
{
if (width == 8)
return "writer.writeByte(" + fieldName + ");";
else if (width == 16)
return "writer.writeInt16(" + fieldName + ");";
else if (width == 32)
return "writer.writeInt32(" + fieldName + ");";
else if (width == 64)
return "writer.writeInt64(" + fieldName + ");";
}
else if (bType->isFloatingPoint())
{
if (width == 32)
return "writer.writeFloat(" + fieldName + ");";
else if (width == 64)
return "writer.writeDouble(" + fieldName + ");";
}
}
else if (theType->isRecordType())
{
const clang::RecordDecl* rDecl = ((clang::RecordType*)theType)->getDecl();
for (const clang::FieldDecl* field : rDecl->fields())
{
if (!field->getNameAsString().compare("clangVec"))
{
const clang::VectorType* vType = (clang::VectorType*)field->getType().getTypePtr();
if (vType->isVectorType())
{
const clang::BuiltinType* eType = (clang::BuiltinType*)vType->getElementType().getTypePtr();
if (!eType->isBuiltinType() || !eType->isFloatingPoint() ||
context.getTypeInfo(eType).Width != 32)
continue;
if (vType->getNumElements() == 3)
return "writer.writeVec3f(" + fieldName + ");";
else if (vType->getNumElements() == 4)
return "writer.writeVec4f(" + fieldName + ");";
}
}
}
}
}
else
{
if (theType->isBuiltinType())
{
const clang::BuiltinType* bType = (clang::BuiltinType*)theType;
if (bType->isUnsignedInteger())
{
if (width == 8)
return "reader.readUByte()";
else if (width == 16)
return "reader.readUint16()";
else if (width == 32)
return "reader.readUint32()";
else if (width == 64)
return "reader.readUint64()";
}
else if (bType->isSignedInteger())
{
if (width == 8)
return "reader.readByte()";
else if (width == 16)
return "reader.readInt16()";
else if (width == 32)
return "reader.readInt32()";
else if (width == 64)
return "reader.readInt64()";
}
else if (bType->isFloatingPoint())
{
if (width == 32)
return "reader.readFloat()";
else if (width == 64)
return "reader.readDouble()";
}
}
else if (theType->isRecordType())
{
const clang::RecordDecl* rDecl = ((clang::RecordType*)theType)->getDecl();
for (const clang::FieldDecl* field : rDecl->fields())
{
if (!field->getNameAsString().compare("clangVec"))
{
const clang::VectorType* vType = (clang::VectorType*)field->getType().getTypePtr();
if (vType->isVectorType())
{
const clang::BuiltinType* eType = (clang::BuiltinType*)vType->getElementType().getTypePtr();
if (!eType->isBuiltinType() || !eType->isFloatingPoint() ||
context.getTypeInfo(eType).Width != 32)
continue;
if (vType->getNumElements() == 3)
return "reader.readVec3f()";
else if (vType->getNumElements() == 4)
return "reader.readVec4f()";
}
}
}
}
}
return std::string();
}
public:
explicit ATDNAEmitVisitor(clang::ASTContext& ctxin,
llvm::raw_fd_ostream& fo)
: context(ctxin), fileOut(fo) {}
bool VisitCXXRecordDecl(clang::CXXRecordDecl* decl)
{
if (decl->isInvalidDecl() || !decl->hasDefinition())
return true;
if (!decl->getNumBases())
return true;
/* First ensure this inherits from struct Athena::io::DNA */
bool foundDNA = false;
for (const clang::CXXBaseSpecifier& base : decl->bases())
{
clang::QualType canonType = base.getType().getCanonicalType();
if (!canonType.getAsString().compare(0, 22, "struct Athena::io::DNA"))
{
foundDNA = true;
break;
}
}
if (!foundDNA)
return true;
for (int p=0 ; p<2 ; ++p)
{
if (p)
fileOut << "void " << decl->getQualifiedNameAsString() << "::write(Athena::IStreamWriter& writer) const\n{\n";
else
fileOut << "void " << decl->getQualifiedNameAsString() << "::read(Athena::IStreamReader& reader)\n{\n";
int currentEndian = -1;
for (const clang::FieldDecl* field : decl->fields())
{
clang::QualType qualType = field->getType();
clang::TypeInfo regTypeInfo = context.getTypeInfo(qualType);
const clang::Type* regType = qualType.getTypePtrOrNull();
if (regType->getTypeClass() == clang::Type::Elaborated)
regType = regType->getUnqualifiedDesugaredType();
if (regType->getTypeClass() == clang::Type::TemplateSpecialization)
{
const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType;
const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl();
const clang::TemplateParameterList* classParms = tsDecl->getTemplateParameters();
if (!tsDecl->getNameAsString().compare("Value"))
{
int endian = -1;
if (classParms->size() >= 2)
{
const clang::NamedDecl* endianParm = classParms->getParam(1);
if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm)
{
const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm;
const clang::Expr* defArg = nttParm->getDefaultArgument();
llvm::APSInt result;
if (defArg->isIntegerConstantExpr(result, context))
endian = result.getSExtValue();
}
}
std::string ioOp;
const clang::TemplateArgument* typeArg = nullptr;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Type)
{
typeArg = &arg;
const clang::Type* type = arg.getAsType().getCanonicalType().getTypePtr();
ioOp = GetOpString(type, regTypeInfo.Width, field->getName().str(), p);
}
else if (arg.getKind() == clang::TemplateArgument::Expression)
{
llvm::APSInt value;
if (arg.getAsExpr()->isIntegerConstantExpr(value, context))
endian = value.getSExtValue();
}
}
if (ioOp.empty())
{
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
if (typeArg)
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*typeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
continue;
}
if (currentEndian != endian)
{
if (endian == 0)
fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n");
else if (endian == 1)
fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n");
currentEndian = endian;
}
if (!p)
fileOut << " " << field->getName() << " = " << ioOp << ";\n";
else
fileOut << " " << ioOp << "\n";
}
else if (!tsDecl->getNameAsString().compare("Vector"))
{
int endian = -1;
if (classParms->size() >= 3)
{
const clang::NamedDecl* endianParm = classParms->getParam(2);
if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm)
{
const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm;
const clang::Expr* defArg = nttParm->getDefaultArgument();
llvm::APSInt result;
if (defArg->isIntegerConstantExpr(result, context))
endian = result.getSExtValue();
}
}
std::string ioOp;
std::string sizeVar;
const clang::TemplateArgument* typeArg = nullptr;
const clang::TemplateArgument* sizeArg = nullptr;
size_t idx = 0;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Type)
{
typeArg = &arg;
const clang::Type* type = arg.getAsType().getCanonicalType().getTypePtr();
clang::TypeInfo typeInfo = context.getTypeInfo(arg.getAsType().getCanonicalType());
ioOp = GetOpString(type, typeInfo.Width, "*it", p);
}
else if (arg.getKind() == clang::TemplateArgument::Expression)
{
const clang::Expr* expr = arg.getAsExpr();
if (idx == 1)
{
sizeArg = &arg;
const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr;
if (uExpr->getStmtClass() == clang::Stmt::UnaryExprOrTypeTraitExprClass &&
uExpr->getKind() == clang::UETT_SizeOf)
{
const clang::Expr* argExpr = uExpr->getArgumentExpr();
while (argExpr->getStmtClass() == clang::Stmt::ParenExprClass)
argExpr = ((clang::ParenExpr*)argExpr)->getSubExpr();
if (argExpr->getStmtClass() == clang::Stmt::DeclRefExprClass)
{
const clang::DeclRefExpr* refExpr = (clang::DeclRefExpr*)argExpr;
sizeVar = refExpr->getFoundDecl()->getNameAsString();
}
}
}
else if (idx == 2)
{
llvm::APSInt value;
if (expr->isIntegerConstantExpr(value, context))
endian = value.getSExtValue();
}
}
++idx;
}
if (ioOp.empty())
{
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
if (typeArg)
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*typeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
continue;
}
if (sizeVar.empty())
{
clang::DiagnosticBuilder diag = context.getDiagnostics().Report(tsDecl->getLocation(), context.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Fatal, "Athena error"));
diag.AddString("Unable to use type '" + tsDecl->getNameAsString() + "' with Athena");
if (sizeArg)
diag.AddSourceRange(clang::CharSourceRange(clang::TemplateArgumentLoc(*sizeArg, clang::TemplateArgumentLocInfo()).getSourceRange(), false));
continue;
}
if (currentEndian != endian)
{
if (endian == 0)
fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n");
else if (endian == 1)
fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n");
currentEndian = endian;
}
if (!p)
{
fileOut << " " << field->getName() << ".clear();\n";
fileOut << " " << field->getName() << ".reserve(" << sizeVar << ");\n";
fileOut << " for (int i=0 ; i<" << sizeVar << " ; ++i)\n " << field->getName() << ".push_back(" << ioOp << ");\n";
}
else
fileOut << " for (int i=0, auto it=" << field->getName() << ".begin() ; i<" << sizeVar << " && it!=" << field->getName() << ".end() ; ++i, ++it)\n " << ioOp << "\n";
}
}
else if (regType->getTypeClass() == clang::Type::Record)
{
const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl();
if (cxxRDecl)
{
for (const clang::CXXBaseSpecifier& base : cxxRDecl->bases())
{
clang::QualType canonType = base.getType().getCanonicalType();
if (!canonType.getAsString().compare(0, 22, "struct Athena::io::DNA"))
{
fileOut << " " << field->getNameAsString() << (p ? ".write(writer);\n" : ".read(reader);\n");
currentEndian = -1;
break;
}
}
}
}
}
fileOut << "}\n\n";
}
return true;
}
};
class ATDNAConsumer : public clang::ASTConsumer
{
ATDNAEmitVisitor emitVisitor;
llvm::raw_fd_ostream& fileOut;
public:
explicit ATDNAConsumer(clang::ASTContext& context, llvm::raw_fd_ostream& fo)
: emitVisitor(context, fo),
fileOut(fo) {}
void HandleTranslationUnit(clang::ASTContext& context)
{
/* Write file head */
fileOut << "/* Auto generated atdna implementation */\n"
"#include <Athena/Global.hpp>\n"
"#include <Athena/IStreamReader.hpp>\n"
"#include <Athena/IStreamWriter.hpp>\n\n";
for (const std::string& inputf : InputFilenames)
fileOut << "#include \"" << inputf << "\"\n";
fileOut << "\n";
/* Second pass - emit file */
emitVisitor.TraverseDecl(context.getTranslationUnitDecl());
}
};
class ATDNAAction : public clang::ASTFrontendAction
{
public:
explicit ATDNAAction() {}
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& compiler,
llvm::StringRef /*filename*/)
{
llvm::raw_fd_ostream* fileout;
if (OutputFilename.size())
fileout = compiler.createOutputFile(OutputFilename, false, true, "", "", true);
else
fileout = compiler.createDefaultOutputFile(false, "a", "cpp");
return std::unique_ptr<clang::ASTConsumer>(new ATDNAConsumer(compiler.getASTContext(), *fileout));
}
};
int main(int argc, const char** argv)
{
llvm::cl::ParseCommandLineOptions(argc, argv, "Athena DNA Generator");
if (Help)
llvm::cl::PrintHelpMessage();
std::vector<std::string> args = {"clang-tool",
"-fsyntax-only",
"-std=c++11"};
args.push_back("-I" + std::string(XSTR(INSTALL_PREFIX)) + "/lib/clang/" + CLANG_VERSION_STRING + "/include");
args.push_back("-I" + std::string(XSTR(INSTALL_PREFIX)) + "/include/Athena");
for (int a=1 ; a<argc ; ++a)
args.push_back(argv[a]);
llvm::IntrusiveRefCntPtr<clang::FileManager> fman(new clang::FileManager(clang::FileSystemOptions()));
clang::tooling::ToolInvocation TI(args, new ATDNAAction, fman.get());
if (TI.run())
return 0;
return -1;
}

32
atdna/test.hpp Normal file
View File

@ -0,0 +1,32 @@
#include <Athena/DNA.hpp>
using namespace Athena;
struct ANCSSubFile : public io::DNA<BigEndian>
{
DECL_DNA
Value<atUint32> sub1;
Value<atUint32> sub2;
};
struct ANCSFile : public io::DNA<BigEndian>
{
DECL_DNA
Value<atUint32> var32;
Value<atUint16> var16;
Value<atVec3f> vec3;
Value<atVec4f> vec4;
struct ANCSNestedSubFile : public io::DNA<BigEndian>
{
DECL_DNA
Value<atUint32> nestSub1;
Value<atUint32> nestSub2;
} nestedSubFile;
ANCSSubFile subFile;
Value<atUint32> arrCount;
Vector<atUint32, sizeof(arrCount)> array;
};

43
include/Athena/DNA.hpp Normal file
View File

@ -0,0 +1,43 @@
#ifndef DNA_HPP
#define DNA_HPP
#include "Global.hpp"
#include "IStreamReader.hpp"
#include "IStreamWriter.hpp"
#include <vector>
#include <functional>
namespace Athena
{
namespace io
{
/**
* @brief Base DNA class used against 'atdna'
*
* Athena bundles a build-tool called 'atdna'. This tool functions
* just like the 'clang' compiler, except it emits
*/
template <Endian DNAE>
struct DNA
{
template <typename T, Endian VE = DNAE>
using Value = T;
template <typename T, size_t cntVar, Endian VE = DNAE>
using Vector = std::vector<T>;
virtual void read(IStreamReader&)=0;
virtual void write(IStreamWriter&) const=0;
};
/** Macro to automatically declare read/write methods in subclasses */
#define DECL_DNA \
void read(Athena::io::IStreamReader&); \
void write(Athena::io::IStreamWriter&) const; \
}
}
#endif // DNA_HPP

View File

@ -73,14 +73,14 @@ typedef struct stat64 stat64_t;
namespace Athena
{
enum class SeekOrigin
enum SeekOrigin
{
Begin,
Current,
End
};
enum class Endian
enum Endian
{
LittleEndian,
BigEndian

View File

@ -56,6 +56,34 @@ typedef unsigned long atUint32;
typedef signed long long atInt64;
typedef unsigned long long atUint64;
// Vector types
#if __SSE__
#include <xmmintrin.h>
#endif
typedef union
{
#if __clang__
float clangVec __attribute__((__vector_size__(12)));
#endif
#if __SSE__
__m128 mVec128;
#endif
float vec[3];
} atVec3f;
typedef union
{
#if __clang__
float clangVec __attribute__((__vector_size__(16)));
#endif
#if __SSE__
__m128 mVec128;
#endif
float vec[4];
} atVec4f;
#ifndef NULL
#ifdef __cplusplus
#define NULL 0