The GtkRadiant sources as originally released under the GPL license.

This commit is contained in:
Travis Bradshaw
2012-01-31 15:20:35 -06:00
commit 0991a5ce8b
1590 changed files with 431941 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
map objects module
==================
Objective:
----------
#1 Turn the md3 code into a module. That is handle all aspects of map objects in
a module. This involves:
- the rendering of the model (sleep mode / shader reload are associated issues)
- the manipulation in the editor (moving, rotating, (scaling?))
#2 Have an API generic enough to support other formats than md3. (md1 / md2 for
multiple games support, any other formats).
What we have:
-------------
What is the current implementation of md3 support? Were are the important
features that we will need to work with?
"misc_model" is the required classname for any map object
entity_t::md3Class
eclass_t *md3Class;
This holds the actual md3 object and the rendering information (tri soup,
shader etc.)
entity_t also has vRotation and vScale which are particular to the model
for selection of the brush (selection is preliminary step before any
manipulation operation), we create a bounding box from the md3 information
and use the entity's brush list as storage for it.
Requirements:
-------------
Some technical requirements go on top of our objective given the existing
implementation. The most important one is that the changes applied to the
core must remain focused around the md3 functionality, and must also lay
out the basics of some wider changes. We can identify some of those changes:
- introducing a more generalized way of selecting and manipulation things
in the editor.
- introducing a more generic way of rendering objects in the editor.
More specifically, the details of rendering and manipulation:
transformation
translate&rotate:
A transformation increment is provided
The object is transformed by a specified increment.
Depending on the object type, the transformations may affect
the local coordinate space transformation instead of the object.
This local transformation is used in selection and rendering.
selection:
ray:
Radiant asks model for its world-relative axis-alignedbounding box.
Radiant does intersection test with this bounding box.
If test shows intersection, radiant gives model a ray_t, model tests
for intersection with ray, model returns bool true if intersection
A selection ray in world-space (origin+direction) is provided.
The object must say whether or not it intersects with the ray.
map objects have a special configuration to test on bounding box or trisoup
this is set in preferences independently from the true/false selection tests
area:
radiant uses a bounding box for area selection. (bounding box can be
infinite in some directions for the 'select tall' operations, in practice
we just make them big enough).
rendering:
geometry:
Radiant tells the object what combination of 4 opengl states is currently active:
none - draw as wireframe
fill - draw as filled
alpha blend - provide an opacity value
texture_2d - provide a texture and texture coordinates
lighting - provide normals, enable/disable smooth shading
The object uses opengl to set up its geometry and to draw itself.
material:
The object provides a material name and is assigned a reference to
a shader that matches the name.
The shader contains the texture ID and the opacity value.
The shader is a reference to an external script and must be refreshed
on request.
Proposed implementation:
========================
changes in shared interfaces (include/ directory):
--------------------------------------------------
The following new interfaces will be added:
most likely those interfaces will be implemented in the module
/*!
something that can be selected
*/
class ISelect
{
bool TestRay(ray_t) = 0
bool TestBox(vec3_t vec_min, vec3_t vec_max) = 0;
}
/*!
something that can be selected for edition
this must be synced with entity epairs
(such as origin and angles keys)
*/
class IEdit
{
void Translate(vec3_t v) = 0;
void Rotate(vec3_t origin, vec3_t angles) = 0;
}
for rendering, the existing IGL2DWindow and IGL3DWindow APIs
we can define
class IRender : public IGL2DWindow, public IGL3DWindow
so that we have the Render2D and Render3D on the same class
entity_t will have to be modified, adding the following struct:
typedef struct entity_interfaces_s
{
ISelect *pSelect
IEdit *pEdit
IRender *pRender
}
entity_interfaces_t;
When one of the pointers inside entity_t::entity_interfaces
is != we will handle the entity differently that what we are
doing by default. We will rely on these APIs for rendering,
manipulation etc.
the AABB issue:
changes in the core:
--------------------
In all cases where the entity_t has to be drawn, tested for selection,
manipulated (translation and rotation), add new code to go through the APIs.
md3 module:
-----------
static function table API
- registering of "model" module
need some minors? "md3" etc.
- BuildEntity(entity_t)
if an entity involved with models is found, core will call this
entity_t::entity_interfaces will be filled with the relevant classes
(NOTE:L we don't have a need right now to manipulate a model that
would not be part of an entity. so let's not try to guess what it
would be like)
CModel
stores the trisoup, local AABBs, references to shaders
(CModel potentially needs a CModelManager to handle
model loads and cached models queries)
CModelEntity implements IRender ISelect IEdit
stores an entity_t*
implements the interfaces pointed to in the entity_t
is reference counted obviously
stores a CModel*, calls up to it with entity information for rendering

33
plugins/md3model/ident.h Normal file
View File

@@ -0,0 +1,33 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_IDENT_H)
#define INCLUDED_IDENT_H
#include <string.h>
// equality comparison for two 4-byte ident strings
inline bool ident_equal(const unsigned char* ident, const unsigned char* other)
{
return ident[0] == other[0] && ident[1] == other[1] && ident[2] == other[2] && ident[3] == other[3];
}
#endif

285
plugins/md3model/md2.cpp Normal file
View File

@@ -0,0 +1,285 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "md2.h"
#include "ifilesystem.h"
#include "imodel.h"
#include "imagelib.h"
#include "bytestreamutils.h"
#include "model.h"
#include "ident.h"
#include "mdlnormals.h"
typedef unsigned char byte;
/*
========================================================================
.MD2 triangle model file format
========================================================================
*/
#define MD2_NUMVERTEXNORMALS 162
#define MD2_MAX_SKINNAME 64
const unsigned char MD2_IDENT[4] = { 'I', 'D', 'P', '2', };
#define MD2_VERSION 8
#define MD2_MAX_TRIANGLES 4096
#define MD2_MAX_VERTS 2048
#define MD2_MAX_FRAMES 512
#define MD2_MAX_MD2SKINS 32
#define MD2_MAX_SKINNAME 64
typedef struct
{
short s;
short t;
} md2St_t;
void istream_read_md2St(PointerInputStream& inputStream, md2St_t& st)
{
st.s = istream_read_int16_le(inputStream);
st.t = istream_read_int16_le(inputStream);
}
typedef struct
{
short index_xyz[3];
short index_st[3];
} md2Triangle_t;
void istream_read_md2Triangle(PointerInputStream& inputStream, md2Triangle_t& triangle)
{
triangle.index_xyz[0] = istream_read_int16_le(inputStream);
triangle.index_xyz[1] = istream_read_int16_le(inputStream);
triangle.index_xyz[2] = istream_read_int16_le(inputStream);
triangle.index_st[0] = istream_read_int16_le(inputStream);
triangle.index_st[1] = istream_read_int16_le(inputStream);
triangle.index_st[2] = istream_read_int16_le(inputStream);
}
typedef struct
{
byte v[3]; // scaled byte to fit in frame mins/maxs
byte lightnormalindex;
} md2XyzNormal_t;
void istream_read_md2XyzNormal(PointerInputStream& inputStream, md2XyzNormal_t& xyz)
{
inputStream.read(xyz.v, 3);
inputStream.read(&xyz.lightnormalindex, 1);
}
#define MD2_XYZNORMAL_V0 0
#define MD2_XYZNORMAL_V1 1
#define MD2_XYZNORMAL_V2 2
#define MD2_XYZNORMAL_LNI 3
#define MD2_XYZNORMAL_SIZE 4
typedef struct
{
float scale[3]; // multiply byte verts by this
float translate[3]; // then add this
char name[16]; // frame name from grabbing
md2XyzNormal_t verts[1]; // variable sized
} md2Frame_t;
void istream_read_md2Frame(PointerInputStream& inputStream, md2Frame_t& frame)
{
frame.scale[0] = istream_read_float32_le(inputStream);
frame.scale[1] = istream_read_float32_le(inputStream);
frame.scale[2] = istream_read_float32_le(inputStream);
frame.translate[0] = istream_read_float32_le(inputStream);
frame.translate[1] = istream_read_float32_le(inputStream);
frame.translate[2] = istream_read_float32_le(inputStream);
inputStream.read(reinterpret_cast<unsigned char*>(frame.name), 16);
}
// the glcmd format:
// a positive integer starts a tristrip command, followed by that many
// vertex structures.
// a negative integer starts a trifan command, followed by -x vertexes
// a zero indicates the end of the command list.
// a vertex consists of a floating point s, a floating point t,
// and an integer vertex index.
typedef struct
{
unsigned char ident[4];
int version;
int skinwidth;
int skinheight;
int framesize; // byte size of each frame
int num_skins;
int num_xyz;
int num_st; // greater than num_xyz for seams
int num_tris;
int num_glcmds; // dwords in strip/fan command list
int num_frames;
int ofs_skins; // each skin is a MAX_SKINNAME string
int ofs_st; // byte offset from start for md2St_t
int ofs_tris; // offset for md2triangle_t
int ofs_frames; // offset for first md2Frame_t
int ofs_glcmds;
int ofs_end; // end of file
} md2Header_t;
void istream_read_md2Header(PointerInputStream& inputStream, md2Header_t& header)
{
inputStream.read(header.ident, 4);
header.version = istream_read_int32_le(inputStream);
header.skinwidth = istream_read_int32_le(inputStream);
header.skinheight = istream_read_int32_le(inputStream);
header.framesize = istream_read_int32_le(inputStream);
header.num_skins = istream_read_int32_le(inputStream);
header.num_xyz = istream_read_int32_le(inputStream);
header.num_st = istream_read_int32_le(inputStream);
header.num_tris = istream_read_int32_le(inputStream);
header.num_glcmds = istream_read_int32_le(inputStream);
header.num_frames = istream_read_int32_le(inputStream);
header.ofs_skins = istream_read_int32_le(inputStream);
header.ofs_st = istream_read_int32_le(inputStream);
header.ofs_tris = istream_read_int32_le(inputStream);
header.ofs_frames = istream_read_int32_le(inputStream);
header.ofs_glcmds = istream_read_int32_le(inputStream);
header.ofs_end = istream_read_int32_le(inputStream);
}
ArbitraryMeshVertex MD2Vertex_construct(const md2Header_t* pHeader, const md2Frame_t* pFrame, const md2XyzNormal_t* xyz, const md2St_t* st)
{
return ArbitraryMeshVertex(
Vertex3f(
xyz->v[0] * pFrame->scale[0] + pFrame->translate[0],
xyz->v[1] * pFrame->scale[1] + pFrame->translate[1],
xyz->v[2] * pFrame->scale[2] + pFrame->translate[2]
),
Normal3f(
g_mdl_normals[xyz->lightnormalindex][0],
g_mdl_normals[xyz->lightnormalindex][1],
g_mdl_normals[xyz->lightnormalindex][2]
),
TexCoord2f(
(float)st->s / pHeader->skinwidth,
(float)st->t / pHeader->skinheight
)
);
}
void MD2Surface_read(Surface& surface, const byte* buffer)
{
md2Header_t header;
{
PointerInputStream inputStream(buffer);
istream_read_md2Header(inputStream, header);
}
{
md2Frame_t frame;
PointerInputStream frameStream(buffer + header.ofs_frames);
istream_read_md2Frame(frameStream, frame);
surface.indices().reserve(header.num_tris * 3);
Array<md2XyzNormal_t> md2Xyz(header.num_xyz);
for(Array<md2XyzNormal_t>::iterator i = md2Xyz.begin(); i != md2Xyz.end(); ++i)
{
istream_read_md2XyzNormal(frameStream, *i);
}
Array<md2St_t> md2St(header.num_st);
PointerInputStream stStream(buffer + header.ofs_st);
for(Array<md2St_t>::iterator i = md2St.begin(); i != md2St.end(); ++i)
{
istream_read_md2St(stStream, *i);
}
UniqueVertexBuffer<ArbitraryMeshVertex> inserter(surface.vertices());
inserter.reserve(header.num_st);
PointerInputStream triangleStream(buffer + header.ofs_tris);
for(int i = 0; i < header.num_tris; ++i)
{
md2Triangle_t triangle;
istream_read_md2Triangle(triangleStream, triangle);
surface.indices().insert(inserter.insert(MD2Vertex_construct(&header, &frame, &md2Xyz[triangle.index_xyz[0]], &md2St[triangle.index_st[0]])));
surface.indices().insert(inserter.insert(MD2Vertex_construct(&header, &frame, &md2Xyz[triangle.index_xyz[1]], &md2St[triangle.index_st[1]])));
surface.indices().insert(inserter.insert(MD2Vertex_construct(&header, &frame, &md2Xyz[triangle.index_xyz[2]], &md2St[triangle.index_st[2]])));
}
}
char skinname[MD2_MAX_SKINNAME];
PointerInputStream inputStream(buffer + header.ofs_skins);
inputStream.read(reinterpret_cast<byte*>(skinname), MD2_MAX_SKINNAME);
surface.setShader(skinname);
surface.updateAABB();
}
void MD2Model_read(Model& model, const byte* buffer)
{
MD2Surface_read(model.newSurface(), buffer);
model.updateAABB();
}
scene::Node& MD2Model_new(const byte* buffer)
{
ModelNode* modelNode = new ModelNode();
MD2Model_read(modelNode->model(), buffer);
return modelNode->node();
}
scene::Node& MD2Model_default()
{
ModelNode* modelNode = new ModelNode();
Model_constructNull(modelNode->model());
return modelNode->node();
}
scene::Node& MD2Model_fromBuffer(unsigned char* buffer)
{
if (!ident_equal(buffer, MD2_IDENT))
{
globalErrorStream() << "MD2 read error: incorrect ident\n";
return MD2Model_default();
}
else
{
return MD2Model_new(buffer);
}
}
scene::Node& loadMD2Model(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return MD2Model_fromBuffer(buffer.buffer);
}

30
plugins/md3model/md2.h Normal file
View File

@@ -0,0 +1,30 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MD2_H)
#define INCLUDED_MD2_H
namespace scene { class Node; }
class ArchiveFile;
scene::Node& loadMD2Model(ArchiveFile& file);
#endif

340
plugins/md3model/md3.cpp Normal file
View File

@@ -0,0 +1,340 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "md3.h"
#include "ifilesystem.h"
#include "imodel.h"
#include "imagelib.h"
#include "bytestreamutils.h"
#include "model.h"
#include "ident.h"
#include "md3normals.h"
// the maximum size of game reletive pathnames
#define MAX_QPATH 64
/*
========================================================================
.MD3 triangle model file format
========================================================================
*/
const unsigned char MD3_IDENT[4] = { 'I', 'D', 'P', '3', };
#define MD3_VERSION 15
// limits
#define MD3_MAX_LODS 4
#define MD3_MAX_TRIANGLES 8192 // per surface
#define MD3_MAX_VERTS 4096 // per surface
#define MD3_MAX_SHADERS 256 // per surface
#define MD3_MAX_FRAMES 1024 // per model
#define MD3_MAX_SURFACES 32 // per model
#define MD3_MAX_TAGS 16 // per frame
// vertex scales
#define MD3_XYZ_SCALE (1.f / 64)
typedef float float3[3];
void istream_read_float3(PointerInputStream& inputStream, float3 f)
{
f[0] = istream_read_float32_le(inputStream);
f[1] = istream_read_float32_le(inputStream);
f[2] = istream_read_float32_le(inputStream);
}
typedef struct md3Frame_s {
float3 bounds[2];
float3 localOrigin;
float radius;
char name[16];
} md3Frame_t;
void istream_read_md3Frame(PointerInputStream& inputStream, md3Frame_t& frame)
{
istream_read_float3(inputStream, frame.bounds[0]);
istream_read_float3(inputStream, frame.bounds[1]);
istream_read_float3(inputStream, frame.localOrigin);
frame.radius = istream_read_float32_le(inputStream);
inputStream.read(reinterpret_cast<unsigned char*>(frame.name), 16);
}
typedef struct md3Tag_s {
char name[MAX_QPATH]; // tag name
float3 origin;
float3 axis[3];
} md3Tag_t;
void istream_read_md3Shader(PointerInputStream& inputStream, md3Tag_t& tag)
{
inputStream.read(reinterpret_cast<unsigned char*>(tag.name), MAX_QPATH);
istream_read_float3(inputStream, tag.origin);
istream_read_float3(inputStream, tag.axis[0]);
istream_read_float3(inputStream, tag.axis[1]);
istream_read_float3(inputStream, tag.axis[2]);
}
/*
** md3Surface_t
**
** CHUNK SIZE
** header sizeof( md3Surface_t )
** shaders sizeof( md3Shader_t ) * numShaders
** triangles[0] sizeof( md3Triangle_t ) * numTriangles
** st sizeof( md3St_t ) * numVerts
** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
*/
typedef struct {
char ident[4]; //
char name[MAX_QPATH]; // polyset name
int flags;
int numFrames; // all surfaces in a model should have the same
int numShaders; // all surfaces in a model should have the same
int numVerts;
int numTriangles;
int ofsTriangles;
int ofsShaders; // offset from start of md3Surface_t
int ofsSt; // texture coords are common for all frames
int ofsXyzNormals; // numVerts * numFrames
int ofsEnd; // next surface follows
} md3Surface_t;
void istream_read_md3Surface(PointerInputStream& inputStream, md3Surface_t& surface)
{
inputStream.read(reinterpret_cast<unsigned char*>(surface.ident), 4);
inputStream.read(reinterpret_cast<unsigned char*>(surface.name), MAX_QPATH);
surface.flags = istream_read_int32_le(inputStream);
surface.numFrames = istream_read_int32_le(inputStream);
surface.numShaders = istream_read_int32_le(inputStream);
surface.numVerts = istream_read_int32_le(inputStream);
surface.numTriangles = istream_read_int32_le(inputStream);
surface.ofsTriangles = istream_read_int32_le(inputStream);
surface.ofsShaders = istream_read_int32_le(inputStream);
surface.ofsSt = istream_read_int32_le(inputStream);
surface.ofsXyzNormals = istream_read_int32_le(inputStream);
surface.ofsEnd = istream_read_int32_le(inputStream);
}
typedef struct {
char name[MAX_QPATH];
int shaderIndex; // for in-game use
} md3Shader_t;
void istream_read_md3Shader(PointerInputStream& inputStream, md3Shader_t& shader)
{
inputStream.read(reinterpret_cast<unsigned char*>(shader.name), MAX_QPATH);
shader.shaderIndex = istream_read_int32_le(inputStream);
}
typedef struct {
int indexes[3];
} md3Triangle_t;
void istream_read_md3Triangle(PointerInputStream& inputStream, md3Triangle_t& triangle)
{
triangle.indexes[0] = istream_read_int32_le(inputStream);
triangle.indexes[1] = istream_read_int32_le(inputStream);
triangle.indexes[2] = istream_read_int32_le(inputStream);
}
typedef struct {
float st[2];
} md3St_t;
void istream_read_md3St(PointerInputStream& inputStream, md3St_t& st)
{
st.st[0] = istream_read_float32_le(inputStream);
st.st[1] = istream_read_float32_le(inputStream);
}
typedef struct {
short xyz[3];
short normal;
} md3XyzNormal_t;
void istream_read_md3XyzNormal(PointerInputStream& inputStream, md3XyzNormal_t& xyz)
{
xyz.xyz[0] = istream_read_int16_le(inputStream);
xyz.xyz[1] = istream_read_int16_le(inputStream);
xyz.xyz[2] = istream_read_int16_le(inputStream);
xyz.normal = istream_read_int16_le(inputStream);
}
typedef struct {
char ident[4];
int version;
char name[MAX_QPATH]; // model name
int flags;
int numFrames;
int numTags;
int numSurfaces;
int numSkins;
int ofsFrames; // offset for first frame
int ofsTags; // numFrames * numTags
int ofsSurfaces; // first surface, others follow
int ofsEnd; // end of file
} md3Header_t;
void istream_read_md3Header(PointerInputStream& inputStream, md3Header_t& header)
{
inputStream.read(reinterpret_cast<unsigned char*>(header.ident), 4);
header.version = istream_read_int32_le(inputStream);
inputStream.read(reinterpret_cast<unsigned char*>(header.name), MAX_QPATH);
header.flags = istream_read_int32_le(inputStream);
header.numFrames = istream_read_int32_le(inputStream);
header.numTags = istream_read_int32_le(inputStream);
header.numSurfaces = istream_read_int32_le(inputStream);
header.numSkins = istream_read_int32_le(inputStream);
header.ofsFrames = istream_read_int32_le(inputStream);
header.ofsTags = istream_read_int32_le(inputStream);
header.ofsSurfaces = istream_read_int32_le(inputStream);
header.ofsEnd = istream_read_int32_le(inputStream);
}
int MD3Surface_read(Surface& surface, unsigned char* buffer)
{
md3Surface_t md3Surface;
{
PointerInputStream inputStream(buffer);
istream_read_md3Surface(inputStream, md3Surface);
}
{
surface.vertices().reserve(md3Surface.numVerts);
PointerInputStream xyzNormalStream(buffer + md3Surface.ofsXyzNormals);
PointerInputStream stStream(buffer + md3Surface.ofsSt);
// read verts into vertex array - xyz, st, normal
for(int i = 0; i < md3Surface.numVerts; i++)
{
md3XyzNormal_t md3Xyz;
istream_read_md3XyzNormal(xyzNormalStream, md3Xyz);
md3St_t md3St;
istream_read_md3St(stStream, md3St);
surface.vertices().push_back(
ArbitraryMeshVertex(
Vertex3f( md3Xyz.xyz[0] * MD3_XYZ_SCALE, md3Xyz.xyz[1] * MD3_XYZ_SCALE, md3Xyz.xyz[2] * MD3_XYZ_SCALE),
DecodeNormal(reinterpret_cast<byte*>(&md3Xyz.normal)),
TexCoord2f(md3St.st[0], md3St.st[1])
)
);
}
}
{
surface.indices().reserve(md3Surface.numTriangles * 3);
PointerInputStream inputStream(buffer + md3Surface.ofsTriangles);
for(int i = 0; i < md3Surface.numTriangles; i++)
{
md3Triangle_t md3Triangle;
istream_read_md3Triangle(inputStream, md3Triangle);
surface.indices().insert(md3Triangle.indexes[0]);
surface.indices().insert(md3Triangle.indexes[1]);
surface.indices().insert(md3Triangle.indexes[2]);
}
}
{
md3Shader_t md3Shader;
{
PointerInputStream inputStream(buffer + md3Surface.ofsShaders);
istream_read_md3Shader(inputStream, md3Shader);
}
surface.setShader(md3Shader.name);
}
surface.updateAABB();
return md3Surface.ofsEnd;
}
void MD3Model_read(Model& model, unsigned char* buffer)
{
md3Header_t md3Header;
{
PointerInputStream inputStream(buffer);
istream_read_md3Header(inputStream, md3Header);
}
unsigned char* surfacePosition = buffer + md3Header.ofsSurfaces;
for(int i = 0; i != md3Header.numSurfaces; ++i)
{
surfacePosition += MD3Surface_read(model.newSurface(), surfacePosition);
}
model.updateAABB();
}
scene::Node& MD3Model_new(unsigned char* buffer)
{
ModelNode* modelNode = new ModelNode();
MD3Model_read(modelNode->model(), buffer);
return modelNode->node();
}
scene::Node& MD3Model_default()
{
ModelNode* modelNode = new ModelNode();
Model_constructNull(modelNode->model());
return modelNode->node();
}
scene::Node& MD3Model_fromBuffer(unsigned char* buffer)
{
if (!ident_equal(buffer, MD3_IDENT))
{
globalErrorStream() << "MD3 read error: incorrect ident\n";
return MD3Model_default();
}
else
{
return MD3Model_new(buffer);
}
}
scene::Node& loadMD3Model(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return MD3Model_fromBuffer(buffer.buffer);
}

29
plugins/md3model/md3.h Normal file
View File

@@ -0,0 +1,29 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MD3_H)
#define INCLUDED_MD3_H
namespace scene { class Node; }
class ArchiveFile;
scene::Node& loadMD3Model(ArchiveFile& file);
#endif

View File

@@ -0,0 +1,218 @@
# Microsoft Developer Studio Project File - Name="md3model" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=md3model - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "md3model.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "md3model.mak" CFG="md3model - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "md3model - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "md3model - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "md3model"
# PROP Scc_LocalPath "..\.."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "md3model - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /O2 /I "..\..\include" /I "..\common" /I "..\..\libs" /I "..\..\..\libxml2\include\\" /I "..\..\..\STLPort\stlport" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "..\..\..\gtk2-win32\lib\glib-2.0\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x40c /d "NDEBUG"
# ADD RSC /l 0x40c /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 mathlib.lib glib-2.0.lib /nologo /dll /machine:I386 /def:".\md3model.def" /libpath:"..\..\libs\mathlib\release" /libpath:"..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Release\md3model.dll "../../install/modules"
# End Special Build Tool
!ELSEIF "$(CFG)" == "md3model - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
F90=df.exe
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "..\..\include" /I "..\..\shared" /I "..\common" /I "..\..\libs" /I "..\..\..\libxml2\include" /I "..\..\..\STLPort\stlport" /I "..\..\..\gtk2-win32\include\glib-2.0" /I "../../../gtk2-win32/lib/glib-2.0/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MAP_EXPORTS" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x40c /d "_DEBUG"
# ADD RSC /l 0x40c /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 mathlib.lib glib-2.0.lib /nologo /dll /debug /machine:I386 /def:".\md3model.def" /pdbtype:sept /libpath:"..\..\libs\mathlib\debug" /libpath:"..\..\..\gtk2-win32\lib\\"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Desc=Copy to dir...
PostBuild_Cmds=copy Debug\md3model.dll "../../install/modules"
# End Special Build Tool
!ENDIF
# Begin Target
# Name "md3model - Win32 Release"
# Name "md3model - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\md2.cpp
# End Source File
# Begin Source File
SOURCE=.\md3.cpp
# End Source File
# Begin Source File
SOURCE=.\md3model.def
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\mdc.cpp
# End Source File
# Begin Source File
SOURCE=.\mdl.cpp
# End Source File
# Begin Source File
SOURCE=.\mdlimage.cpp
# End Source File
# Begin Source File
SOURCE=.\plugin.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Group "API"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\include\ifilesystem.h
# End Source File
# Begin Source File
SOURCE=..\..\include\igl.h
# End Source File
# Begin Source File
SOURCE=..\..\include\imodel.h
# End Source File
# Begin Source File
SOURCE=..\..\include\ishaders.h
# End Source File
# Begin Source File
SOURCE=..\..\include\isurface.h
# End Source File
# Begin Source File
SOURCE=..\..\include\qerplugin.h
# End Source File
# Begin Source File
SOURCE=..\..\include\qertypes.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\ident.h
# End Source File
# Begin Source File
SOURCE=.\md2.h
# End Source File
# Begin Source File
SOURCE=.\md3.h
# End Source File
# Begin Source File
SOURCE=.\md3normals.h
# End Source File
# Begin Source File
SOURCE=.\mdc.h
# End Source File
# Begin Source File
SOURCE=.\mdl.h
# End Source File
# Begin Source File
SOURCE=.\mdlnormals.h
# End Source File
# Begin Source File
SOURCE=.\model.h
# End Source File
# Begin Source File
SOURCE=.\plugin.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Source File
SOURCE=.\Conscript
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,23 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "md3normals.h"

View File

@@ -0,0 +1,45 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MD3NORMALS_H)
#define INCLUDED_MD3NORMALS_H
#include "render.h"
typedef unsigned char byte;
// latitude-longditude to normal conversion
inline Normal3f DecodeNormal(const byte bytes[2])
{
double lat = bytes[0] * (c_pi/128.0);
double lng = bytes[1] * (c_pi/128.0);
return Normal3f(
static_cast<float>(cos(lat) * sin(lng)),
static_cast<float>(sin(lat) * sin(lng)),
static_cast<float>(cos(lng))
);
}
#endif

454
plugins/md3model/md5.cpp Normal file
View File

@@ -0,0 +1,454 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "md5.h"
#include "iscriplib.h"
#include "imodel.h"
#include "archivelib.h"
#include "stringio.h"
#include "model.h"
#define MD5_RETURN_FALSE_IF_FAIL(expression) if(!(expression)) { globalErrorStream() << "md5 parse failed: " #expression "\n"; return false; } else
bool MD5_parseToken(Tokeniser& tokeniser, const char* string)
{
const char* token = tokeniser.getToken();
MD5_RETURN_FALSE_IF_FAIL(token != 0);
return string_equal(token, string);
}
bool MD5_parseFloat(Tokeniser& tokeniser, float& f)
{
const char* token = tokeniser.getToken();
MD5_RETURN_FALSE_IF_FAIL(token != 0);
return string_parse_float(token, f);
}
bool MD5_parseString(Tokeniser& tokeniser, const char*& s)
{
const char* token = tokeniser.getToken();
MD5_RETURN_FALSE_IF_FAIL(token != 0);
s = token;
return true;
}
bool MD5_parseInteger(Tokeniser& tokeniser, int& i)
{
const char* token = tokeniser.getToken();
MD5_RETURN_FALSE_IF_FAIL(token != 0);
return string_parse_int(token, i);
}
bool MD5_parseSize(Tokeniser& tokeniser, std::size_t& i)
{
const char* token = tokeniser.getToken();
MD5_RETURN_FALSE_IF_FAIL(token != 0);
return string_parse_size(token, i);
}
bool MD5_parseVector3(Tokeniser& tokeniser, Vector3& v)
{
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "("));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseFloat(tokeniser, v.x()));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseFloat(tokeniser, v.y()));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseFloat(tokeniser, v.z()));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, ")"));
return true;
}
template<typename Element>
inline Element float_squared(const Element& f)
{
return f * f;
}
class MD5Joint
{
public:
int parent;
Vector3 position;
Vector4 rotation;
};
typedef Array<MD5Joint> MD5Joints;
class MD5Vert
{
public:
std::size_t index;
float u;
float v;
std::size_t weight_index;
std::size_t weight_count;
};
typedef Array<MD5Vert> MD5Verts;
class MD5Tri
{
public:
std::size_t index;
std::size_t a;
std::size_t b;
std::size_t c;
};
typedef Array<MD5Tri> MD5Tris;
class MD5Weight
{
public:
std::size_t index;
std::size_t joint;
float t;
Vector3 v;
};
typedef Array<MD5Weight> MD5Weights;
typedef float MD5Component;
typedef Array<MD5Component> MD5Components;
class MD5Frame
{
public:
MD5Components m_components;
};
typedef Array<MD5Weight> MD5Weights;
bool MD5_parseVersion(Tokeniser& tokeniser)
{
{
const char* versionKey = tokeniser.getToken();
if(versionKey == 0 || !string_equal(versionKey, "MD5Version"))
{
globalErrorStream() << "not a valid md5 file\n";
return false;
}
}
{
const char* versionValue = tokeniser.getToken();
if(versionValue == 0 || !string_equal(versionValue, "10"))
{
globalErrorStream() << "only md5 version 10 supported\n";
return false;
}
}
return true;
}
bool MD5Anim_parse(Tokeniser& tokeniser)
{
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVersion(tokeniser));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "commandline"));
const char* commandline;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseString(tokeniser, commandline));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numFrames"));
std::size_t numFrames;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numFrames));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numJoints"));
std::size_t numJoints;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numJoints));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "frameRate"));
std::size_t frameRate;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, frameRate));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numAnimatedComponents"));
std::size_t numAnimatedComponents;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numAnimatedComponents));
tokeniser.nextLine();
// parse heirarchy
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "hierarchy"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
tokeniser.nextLine();
for(std::size_t i = 0; i < numJoints; ++i)
{
const char* name;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseString(tokeniser, name));
int parent;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseInteger(tokeniser, parent));
std::size_t flags;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, flags));
std::size_t index;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, index));
tokeniser.nextLine();
}
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
tokeniser.nextLine();
// parse bounds
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "bounds"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
tokeniser.nextLine();
for(std::size_t i = 0; i < numFrames; ++i)
{
Vector3 mins;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, mins));
Vector3 maxs;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, maxs));
tokeniser.nextLine();
}
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
tokeniser.nextLine();
// parse baseframe
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "baseframe"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
tokeniser.nextLine();
for(std::size_t i = 0; i < numJoints; ++i)
{
Vector3 position;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, position));
Vector3 rotation;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, rotation));
tokeniser.nextLine();
}
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
tokeniser.nextLine();
// parse frames
for(std::size_t i = 0; i < numFrames; ++i)
{
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "frame"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
tokeniser.nextLine();
for(std::size_t i = 0; i < numAnimatedComponents; ++i)
{
float component;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseFloat(tokeniser, component));
tokeniser.nextLine();
}
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
tokeniser.nextLine();
}
return true;
}
bool MD5Model_parse(Model& model, Tokeniser& tokeniser)
{
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVersion(tokeniser));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "commandline"));
const char* commandline;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseString(tokeniser, commandline));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numJoints"));
std::size_t numJoints;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numJoints));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numMeshes"));
std::size_t numMeshes;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numMeshes));
tokeniser.nextLine();
MD5Joints joints(numJoints);
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "joints"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
tokeniser.nextLine();
for(MD5Joints::iterator i = joints.begin(); i != joints.end(); ++i)
{
const char* jointName;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseString(tokeniser, jointName));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseInteger(tokeniser, (*i).parent));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, (*i).position));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, (*i).rotation));
(*i).rotation.w() = -static_cast<float>(sqrt(1.0f - (float_squared((*i).rotation.x()) + float_squared((*i).rotation.y()) + float_squared((*i).rotation.z()))));
tokeniser.nextLine();
}
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
tokeniser.nextLine();
for(std::size_t i = 0; i < numMeshes; ++i)
{
Surface& surface = model.newSurface();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "mesh"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "{"));
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "shader"));
const char* shader;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseString(tokeniser, shader));
surface.setShader(shader);
tokeniser.nextLine();
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numverts"));
std::size_t numVerts;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numVerts));
tokeniser.nextLine();
MD5Verts verts(numVerts);
for(MD5Verts::iterator j = verts.begin(); j != verts.end(); ++j)
{
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "vert"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).index));
MD5_RETURN_FALSE_IF_FAIL((*j).index == std::size_t(j - verts.begin()));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "("));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseFloat(tokeniser, (*j).u));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseFloat(tokeniser, (*j).v));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, ")"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).weight_index));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).weight_count));
tokeniser.nextLine();
}
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numtris"));
std::size_t numTris;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numTris));
tokeniser.nextLine();
MD5Tris tris(numTris);
for(MD5Tris::iterator j = tris.begin(); j != tris.end(); ++j)
{
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "tri"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).index));
MD5_RETURN_FALSE_IF_FAIL((*j).index == std::size_t(j - tris.begin()));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).a));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).b));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).c));
tokeniser.nextLine();
}
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "numweights"));
std::size_t numWeights;
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, numWeights));
tokeniser.nextLine();
MD5Weights weights(numWeights);
for(MD5Weights::iterator j = weights.begin(); j != weights.end(); ++j)
{
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "weight"));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).index));
MD5_RETURN_FALSE_IF_FAIL((*j).index == std::size_t(j - weights.begin()));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseSize(tokeniser, (*j).joint));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseFloat(tokeniser, (*j).t));
MD5_RETURN_FALSE_IF_FAIL(MD5_parseVector3(tokeniser, (*j).v));
tokeniser.nextLine();
}
MD5_RETURN_FALSE_IF_FAIL(MD5_parseToken(tokeniser, "}"));
tokeniser.nextLine();
for(MD5Verts::iterator j = verts.begin(); j != verts.end(); ++j)
{
MD5Vert& vert = (*j);
Vector3 skinned(0, 0, 0);
for(std::size_t k = 0; k != vert.weight_count; ++k)
{
MD5Weight& weight = weights[vert.weight_index + k];
MD5Joint& joint = joints[weight.joint];
skinned += (quaternion_transformed_point(joint.rotation, weight.v) + joint.position) * weight.t;
}
surface.vertices().push_back(ArbitraryMeshVertex(vertex3f_for_vector3(skinned), Normal3f(0, 0, 0), TexCoord2f(vert.u, vert.v)));
}
for(MD5Tris::iterator j = tris.begin(); j != tris.end(); ++j)
{
MD5Tri& tri = (*j);
surface.indices().insert(RenderIndex(tri.a));
surface.indices().insert(RenderIndex(tri.b));
surface.indices().insert(RenderIndex(tri.c));
}
for(Surface::indices_t::iterator j = surface.indices().begin(); j != surface.indices().end(); j += 3)
{
ArbitraryMeshVertex& a = surface.vertices()[*(j + 0)];
ArbitraryMeshVertex& b = surface.vertices()[*(j + 1)];
ArbitraryMeshVertex& c = surface.vertices()[*(j + 2)];
Vector3 weightedNormal(
vector3_cross(
reinterpret_cast<const Vector3&>(c.vertex) - reinterpret_cast<const Vector3&>(a.vertex),
reinterpret_cast<const Vector3&>(b.vertex) - reinterpret_cast<const Vector3&>(a.vertex)
)
);
reinterpret_cast<Vector3&>(a.normal) += weightedNormal;
reinterpret_cast<Vector3&>(b.normal) += weightedNormal;
reinterpret_cast<Vector3&>(c.normal) += weightedNormal;
}
for(Surface::vertices_t::iterator j = surface.vertices().begin(); j != surface.vertices().end(); ++j)
{
vector3_normalise(reinterpret_cast<Vector3&>((*j).normal));
}
surface.updateAABB();
}
model.updateAABB();
return true;
}
void MD5Model_construct(Model& model, TextInputStream& inputStream)
{
Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewSimpleTokeniser(inputStream);
MD5Model_parse(model, tokeniser);
tokeniser.release();
}
scene::Node& MD5Model_new(TextInputStream& inputStream)
{
ModelNode* modelNode = new ModelNode();
MD5Model_construct(modelNode->model(), inputStream);
return modelNode->node();
}
scene::Node& loadMD5Model(ArchiveFile& file)
{
BinaryToTextInputStream<InputStream> inputStream(file.getInputStream());
return MD5Model_new(inputStream);
}

29
plugins/md3model/md5.h Normal file
View File

@@ -0,0 +1,29 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MD5_H)
#define INCLUDED_MD5_H
namespace scene { class Node; }
class ArchiveFile;
scene::Node& loadMD5Model(ArchiveFile& file);
#endif

292
plugins/md3model/mdc.cpp Normal file
View File

@@ -0,0 +1,292 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mdc.h"
#include "ifilesystem.h"
#include "imodel.h"
#include "imagelib.h"
#include "bytestreamutils.h"
#include "model.h"
#include "ident.h"
#include "md3normals.h"
const unsigned char MDC_IDENT[4] = { 'I', 'D', 'P', 'C', };
const float MDC_XYZ_SCALE = 0.015625f;
#define MAX_QPATH 64 // max length of a quake game pathname
typedef float float3[3];
struct mdcTriangle_t
{
unsigned int indexes[3]; // not my spelling
};
void istream_read_mdcTriangle(PointerInputStream& inputStream, mdcTriangle_t& triangle)
{
triangle.indexes[0] = istream_read_uint32_le(inputStream);
triangle.indexes[1] = istream_read_uint32_le(inputStream);
triangle.indexes[2] = istream_read_uint32_le(inputStream);
}
struct mdcXyzNormal_t
{
short xyz[3]; // divide by 64
short normal; // packed same way as md3
};
void istream_read_mdcXyzNormal(PointerInputStream& inputStream, mdcXyzNormal_t& xyz)
{
xyz.xyz[0] = istream_read_int16_le(inputStream);
xyz.xyz[1] = istream_read_int16_le(inputStream);
xyz.xyz[2] = istream_read_int16_le(inputStream);
xyz.normal = istream_read_int16_le(inputStream);
}
struct mdcSt_t
{
float st[2]; // may need to reverse t
};
void istream_read_mdcSt(PointerInputStream& inputStream, mdcSt_t& st)
{
st.st[0] = istream_read_float32_le(inputStream);
st.st[1] = istream_read_float32_le(inputStream);
}
struct mdcShader_t
{
char name[MAX_QPATH];
unsigned int flags;
};
void istream_read_mdcShader(PointerInputStream& inputStream, mdcShader_t& shader)
{
inputStream.read(reinterpret_cast<byte*>(shader.name), MAX_QPATH);
shader.flags = istream_read_uint32_le(inputStream);
}
struct mdcTagName_t
{
char name[MAX_QPATH];
};
struct mdcTagFrame_t
{
short xyz[3]; // divide by 64
short angles[3]; // euler in z x y order... deg = * (360.0 / 32767.0) .. rad = * (PI / 32767.0)
};
struct mdcFrame_t
{
float3 bboxMin;
float3 bboxMax;
float3 localOrigin;
float radius;
char name[16];
};
struct mdcSurface_t
{
byte ident[4];
char name[MAX_QPATH];
unsigned int flags;
unsigned int numCompFrames;
unsigned int numBaseFrames;
unsigned int numShaders;
unsigned int numVerts;
unsigned int numTriangles;
unsigned int ofsTriangles;
unsigned int ofsShaders;
unsigned int ofsSt;
unsigned int ofsXyzNormals;
unsigned int ofsCompVerts;
unsigned int ofsFrameBaseFrames;
unsigned int ofsFrameCompFrames;
unsigned int ofsEnd;
};
void istream_read_mdcSurface(PointerInputStream& inputStream, mdcSurface_t& surface)
{
inputStream.read(surface.ident, 4);
inputStream.read(reinterpret_cast<byte*>(surface.name), MAX_QPATH);
surface.flags = istream_read_uint32_le(inputStream);
surface.numCompFrames = istream_read_uint32_le(inputStream);
surface.numBaseFrames = istream_read_uint32_le(inputStream);
surface.numShaders = istream_read_uint32_le(inputStream);
surface.numVerts = istream_read_uint32_le(inputStream);
surface.numTriangles = istream_read_uint32_le(inputStream);
surface.ofsTriangles = istream_read_uint32_le(inputStream);
surface.ofsShaders = istream_read_uint32_le(inputStream);
surface.ofsSt = istream_read_uint32_le(inputStream);
surface.ofsXyzNormals = istream_read_uint32_le(inputStream);
surface.ofsCompVerts = istream_read_uint32_le(inputStream);
surface.ofsFrameBaseFrames = istream_read_uint32_le(inputStream);
surface.ofsFrameCompFrames = istream_read_uint32_le(inputStream);
surface.ofsEnd = istream_read_uint32_le(inputStream);
}
struct mdcHeader_t
{
byte ident[4];
unsigned int version;
char name[MAX_QPATH];
unsigned int flags;
unsigned int numFrames;
unsigned int numTags;
unsigned int numSurfaces;
unsigned int numSkins;
unsigned int ofsFrames;
unsigned int ofsTagNames;
unsigned int ofsTags;
unsigned int ofsSurfaces;
unsigned int ofsEnd;
};
void istream_read_mdcHeader(PointerInputStream& inputStream, mdcHeader_t& header)
{
inputStream.read(header.ident, 4);
header.version = istream_read_uint32_le(inputStream);
inputStream.read(reinterpret_cast<byte*>(header.name), MAX_QPATH);
header.flags = istream_read_uint32_le(inputStream);
header.numFrames = istream_read_uint32_le(inputStream);
header.numTags = istream_read_uint32_le(inputStream);
header.numSurfaces = istream_read_uint32_le(inputStream);
header.numSkins = istream_read_uint32_le(inputStream);
header.ofsFrames = istream_read_uint32_le(inputStream);
header.ofsTagNames = istream_read_uint32_le(inputStream);
header.ofsTags = istream_read_uint32_le(inputStream);
header.ofsSurfaces = istream_read_uint32_le(inputStream);
header.ofsEnd = istream_read_uint32_le(inputStream);
}
unsigned int MDCSurface_read(Surface& surface, const byte* buffer)
{
mdcSurface_t mdcSurface;
{
PointerInputStream inputStream(buffer);
istream_read_mdcSurface(inputStream, mdcSurface);
}
{
surface.vertices().reserve(mdcSurface.numVerts);
PointerInputStream xyzStream(buffer + mdcSurface.ofsXyzNormals);
PointerInputStream stStream(buffer + mdcSurface.ofsSt);
// read verts into vertex array - xyz, st, normal
for(std::size_t i = 0; i < mdcSurface.numVerts; i++)
{
mdcXyzNormal_t mdcXyzNormal;
istream_read_mdcXyzNormal(xyzStream, mdcXyzNormal);
mdcSt_t mdcSt;
istream_read_mdcSt(stStream, mdcSt);
surface.vertices().push_back(
ArbitraryMeshVertex(
Vertex3f( mdcXyzNormal.xyz[0] * MDC_XYZ_SCALE, mdcXyzNormal.xyz[1] * MDC_XYZ_SCALE, mdcXyzNormal.xyz[2] * MDC_XYZ_SCALE),
DecodeNormal(reinterpret_cast<byte*>(&mdcXyzNormal.normal)),
TexCoord2f(mdcSt.st[0], mdcSt.st[1])
)
);
}
}
{
surface.indices().reserve(mdcSurface.numTriangles * 3);
PointerInputStream triangleStream(buffer + mdcSurface.ofsTriangles);
for(std::size_t i = 0; i < mdcSurface.numTriangles; i++)
{
mdcTriangle_t triangle;
istream_read_mdcTriangle(triangleStream, triangle);
surface.indices().insert(triangle.indexes[0]);
surface.indices().insert(triangle.indexes[1]);
surface.indices().insert(triangle.indexes[2]);
}
}
{
mdcShader_t shader;
PointerInputStream inputStream(buffer + mdcSurface.ofsShaders);
istream_read_mdcShader(inputStream, shader);
surface.setShader(shader.name);
}
surface.updateAABB();
return mdcSurface.ofsEnd;
}
void MDCModel_read(Model& model, const byte* buffer)
{
mdcHeader_t header;
{
PointerInputStream inputStream(buffer);
istream_read_mdcHeader(inputStream, header);
}
const byte* surfacePosition = buffer + header.ofsSurfaces;
for(std::size_t i = 0; i < header.numSurfaces; i++)
{
surfacePosition += MDCSurface_read(model.newSurface(), surfacePosition);
}
model.updateAABB();
}
scene::Node& MDCModel_new(const byte* buffer)
{
ModelNode* modelNode = new ModelNode();
MDCModel_read(modelNode->model(), buffer);
return modelNode->node();
}
scene::Node& MDCModel_default()
{
ModelNode* modelNode = new ModelNode();
Model_constructNull(modelNode->model());
return modelNode->node();
}
scene::Node& MDCModel_fromBuffer(unsigned char* buffer)
{
if (!ident_equal(buffer, MDC_IDENT))
{
globalErrorStream() << "MDC read error: incorrect ident\n";
return MDCModel_default();
}
else
{
return MDCModel_new(buffer);
}
}
scene::Node& loadMDCModel(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return MDCModel_fromBuffer(buffer.buffer);
}

30
plugins/md3model/mdc.h Normal file
View File

@@ -0,0 +1,30 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MDC_H)
#define INCLUDED_MDC_H
namespace scene { class Node; }
class ArchiveFile;
scene::Node& loadMDCModel(ArchiveFile& file);
#endif

241
plugins/md3model/mdl.cpp Normal file
View File

@@ -0,0 +1,241 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mdl.h"
#include "ifilesystem.h"
#include "imodel.h"
#include "imagelib.h"
#include "bytestreamutils.h"
#include "model.h"
#include "ident.h"
#include "mdlnormals.h"
#include "mdlformat.h"
void istream_read_mdlHeader(PointerInputStream& inputStream, mdlHeader_t& header)
{
inputStream.read(header.ident, 4);
header.version = istream_read_int32_le(inputStream);
header.scale[0] = istream_read_float32_le(inputStream);
header.scale[1] = istream_read_float32_le(inputStream);
header.scale[2] = istream_read_float32_le(inputStream);
header.scale_origin[0] = istream_read_float32_le(inputStream);
header.scale_origin[1] = istream_read_float32_le(inputStream);
header.scale_origin[2] = istream_read_float32_le(inputStream);
header.boundingradius = istream_read_float32_le(inputStream);
header.eyeposition[0] = istream_read_float32_le(inputStream);
header.eyeposition[1] = istream_read_float32_le(inputStream);
header.eyeposition[2] = istream_read_float32_le(inputStream);
header.numskins = istream_read_int32_le(inputStream);
header.skinwidth = istream_read_int32_le(inputStream);
header.skinheight = istream_read_int32_le(inputStream);
header.numverts = istream_read_int32_le(inputStream);
header.numtris = istream_read_int32_le(inputStream);
header.numframes = istream_read_int32_le(inputStream);
header.synctype = istream_read_int32_le(inputStream);
header.flags = istream_read_int32_le(inputStream);
header.size = istream_read_float32_le(inputStream);
}
inline ArbitraryMeshVertex MDLVertex_construct(const mdlHeader_t& header, const mdlXyzNormal_t& xyz, const mdlSt_t& st, bool facesfront)
{
return ArbitraryMeshVertex(
Vertex3f(
xyz.v[0] * header.scale[0] + header.scale_origin[0],
xyz.v[1] * header.scale[1] + header.scale_origin[1],
xyz.v[2] * header.scale[2] + header.scale_origin[2]
),
Normal3f(
g_mdl_normals[xyz.lightnormalindex][0],
g_mdl_normals[xyz.lightnormalindex][1],
g_mdl_normals[xyz.lightnormalindex][2]
),
TexCoord2f(
((float)st.s / header.skinwidth) + ((st.onseam == MDL_ONSEAM && !facesfront) ? 0.5f : 0.0f),
(float)st.t / header.skinheight
)
);
}
class mdlVertex_t
{
public:
inline mdlVertex_t(int vertindex, int facesfront)
: m_vertindex(vertindex), m_facesfront(facesfront)
{}
inline bool operator<(const mdlVertex_t& other) const
{
if(m_facesfront < other.m_facesfront)
return true;
if(other.m_facesfront < m_facesfront)
return false;
if(m_vertindex < other.m_vertindex)
return true;
if(other.m_vertindex < m_vertindex)
return false;
return false;
}
inline bool operator==(const mdlVertex_t& other) const
{
return m_vertindex == other.m_vertindex
&& m_facesfront == other.m_facesfront;
}
int m_vertindex;
int m_facesfront;
};
typedef const mdlTriangle_t* mdlTriangleIterator;
void MDLSurface_read(Surface& surface, const byte* buffer, const char* name)
{
mdlHeader_t header;
PointerInputStream inputStream(buffer);
istream_read_mdlHeader(inputStream, header);
for(int i = 0; i < header.numskins; ++i)
{
switch(istream_read_int32_le(inputStream))
{
case MDL_SKIN_SINGLE:
inputStream.seek(header.skinwidth * header.skinheight);
break;
case MDL_SKIN_GROUP:
int numskins = istream_read_int32_le(inputStream);
inputStream.seek(numskins * (4 + (header.skinwidth * header.skinheight)));
break;
}
}
Array<mdlSt_t> mdlSts(header.numverts);
for(Array<mdlSt_t>::iterator i = mdlSts.begin(); i != mdlSts.end(); ++i)
{
(*i).onseam = istream_read_int32_le(inputStream);
(*i).s = istream_read_int32_le(inputStream);
(*i).t = istream_read_int32_le(inputStream);
}
Array<mdlTriangle_t> mdlTriangles(header.numtris);
for(Array<mdlTriangle_t>::iterator i = mdlTriangles.begin(); i != mdlTriangles.end(); ++i)
{
(*i).facesfront = istream_read_int32_le(inputStream);
(*i).vertindex[0] = istream_read_int32_le(inputStream);
(*i).vertindex[1] = istream_read_int32_le(inputStream);
(*i).vertindex[2] = istream_read_int32_le(inputStream);
}
{
bool found = false;
for(int i = 0; i < header.numframes && found == false; i++)
{
switch(istream_read_int32_le(inputStream))
{
case MDL_FRAME_SINGLE:
inputStream.seek(MDL_FRAME_SIZE);
found = true;
break;
case MDL_FRAME_GROUP:
int numframes = istream_read_int32_le(inputStream);
inputStream.seek((MDL_XYZNORMAL_SIZE * 2) + (numframes * 4));
found = true;
break;
}
}
}
Array<mdlXyzNormal_t> mdlXyzNormals(header.numtris);
for(Array<mdlXyzNormal_t>::iterator i = mdlXyzNormals.begin(); i != mdlXyzNormals.end(); ++i)
{
inputStream.read((*i).v, 3);
inputStream.read(&(*i).lightnormalindex, 1);
}
{
VertexBuffer<mdlVertex_t> mdl_vertices;
{
UniqueVertexBuffer<mdlVertex_t> inserter(mdl_vertices);
for(Array<mdlTriangle_t>::iterator i = mdlTriangles.begin(); i != mdlTriangles.end(); ++i)
{
surface.indices().insert(inserter.insert(mdlVertex_t((*i).vertindex[0], (*i).facesfront)));
surface.indices().insert(inserter.insert(mdlVertex_t((*i).vertindex[1], (*i).facesfront)));
surface.indices().insert(inserter.insert(mdlVertex_t((*i).vertindex[2], (*i).facesfront)));
}
}
{
surface.vertices().reserve(mdl_vertices.size());
for(VertexBuffer<mdlVertex_t>::iterator i = mdl_vertices.begin(); i != mdl_vertices.end(); ++i)
{
surface.vertices().push_back(MDLVertex_construct(header, mdlXyzNormals[(*i).m_vertindex], mdlSts[(*i).m_vertindex], (*i).m_facesfront == MDL_FACES_FRONT));
}
}
}
surface.setShader(name);
surface.updateAABB();
}
void MDLModel_read(Model& model, const byte* buffer, const char* name)
{
MDLSurface_read(model.newSurface(), buffer, name);
model.updateAABB();
}
scene::Node& MDLModel_new(const byte* buffer, const char* name)
{
ModelNode* modelNode = new ModelNode();
MDLModel_read(modelNode->model(), buffer, name);
return modelNode->node();
}
scene::Node& MDLModel_default()
{
ModelNode* modelNode = new ModelNode();
Model_constructNull(modelNode->model());
return modelNode->node();
}
scene::Node& MDLModel_fromBuffer(unsigned char* buffer, const char* name)
{
if (!ident_equal(buffer, MDL_IDENT))
{
globalErrorStream() << "MDL read error: incorrect ident\n";
return MDLModel_default();
}
else
{
return MDLModel_new(buffer, name);
}
}
scene::Node& loadMDLModel(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return MDLModel_fromBuffer(buffer.buffer, file.getName());
}

29
plugins/md3model/mdl.h Normal file
View File

@@ -0,0 +1,29 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MDL_H)
#define INCLUDED_MDL_H
namespace scene { class Node; }
class ArchiveFile;
scene::Node& loadMDLModel(ArchiveFile& file);
#endif

View File

@@ -0,0 +1,23 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mdlformat.h"

View File

@@ -0,0 +1,118 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MDLFORMAT_H)
#define INCLUDED_MDLFORMAT_H
typedef unsigned char byte;
const unsigned char MDL_IDENT[4] = { 'I', 'D', 'P', 'O', };
#define MDL_VERSION 6
#define MDL_ONSEAM 0x0020
typedef enum { MDL_FRAME_SINGLE=0, MDL_FRAME_GROUP } aliasframetype_t;
typedef enum { MDL_SKIN_SINGLE=0, MDL_SKIN_GROUP } aliasskintype_t;
typedef float float3[3];
typedef struct {
byte ident[4];
int version;
float3 scale;
float3 scale_origin;
float boundingradius;
float3 eyeposition;
int numskins;
int skinwidth;
int skinheight;
int numverts;
int numtris;
int numframes;
int synctype;
int flags;
float size;
} mdlHeader_t;
// TODO: could be shorts
typedef struct {
int onseam;
int s;
int t;
} mdlSt_t;
typedef struct dtriangle_s {
int facesfront;
int vertindex[3];
} mdlTriangle_t;
#define MDL_FACES_FRONT 1
// This mirrors trivert_t in trilib.h, is present so Quake knows how to
// load this data
typedef struct {
byte v[3];
byte lightnormalindex;
} mdlXyzNormal_t;
const int MDL_XYZNORMAL_SIZE = 4;
typedef struct {
mdlXyzNormal_t bboxmin; // lightnormal isn't used
mdlXyzNormal_t bboxmax; // lightnormal isn't used
char name[16]; // frame name from grabbing
} mdlFrame_t;
const int MDL_FRAME_SIZE = (MDL_XYZNORMAL_SIZE * 2) + 16;
typedef struct {
int numframes;
mdlXyzNormal_t bboxmin; // lightnormal isn't used
mdlXyzNormal_t bboxmax; // lightnormal isn't used
} mdlFrameGroup_t;
const int MDL_FRAMEGROUP_SIZE = 4 + (MDL_XYZNORMAL_SIZE * 2);
typedef struct {
int numskins;
} mdlSkinGroup_t;
typedef struct {
float interval;
} mdlFrameInterval_t;
typedef struct {
float interval;
} mdlSkinInterval_t;
typedef struct {
aliasframetype_t type;
} mdlFrameType_t;
typedef struct {
aliasskintype_t type;
} mdlSkinType_t;
#endif

View File

@@ -0,0 +1,160 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mdlimage.h"
#include <math.h>
#include <stdlib.h>
#include "ifilesystem.h"
#include "bytestreamutils.h"
#include "stream/textstream.h"
#include "imagelib.h"
#include "mdlformat.h"
#include "ident.h"
unsigned char mdl_palette[768];
/*
==============
Texture_InitPalette
==============
*/
void Texture_InitPalette (byte *pal)
{
int r,g,b;
int i;
int inf;
byte gammatable[256];
double gamma;
gamma = 1.0;//g_qeglobals.d_savedinfo.fGamma;
if (gamma == 1.0)
{
for (i=0 ; i<256 ; i++)
gammatable[i] = i;
} else
{
for (i=0 ; i<256 ; i++)
{
inf = (int)(255 * pow ( (i+0.5)/255.5 , gamma ) + 0.5);
if (inf < 0)
inf = 0;
if (inf > 255)
inf = 255;
gammatable[i] = inf;
}
}
for (i=0 ; i<256 ; i++)
{
r = gammatable[pal[0]];
g = gammatable[pal[1]];
b = gammatable[pal[2]];
pal += 3;
//v = (r<<24) + (g<<16) + (b<<8) + 255;
//v = BigLong (v);
//mdl_palette[i] = v;
mdl_palette[i*3+0] = r;
mdl_palette[i*3+1] = g;
mdl_palette[i*3+2] = b;
}
}
bool LoadPalette()
{
unsigned char* buffer;
//int len =
vfsLoadFile ("gfx/palette.lmp", (void **) &buffer);
if (buffer == 0)
return false;
Texture_InitPalette(buffer);
vfsFreeFile(buffer);
return true;
}
Image* LoadMDLImageBuff(byte* buffer)
{
if(!LoadPalette())
{
return 0;
}
if(!ident_equal(buffer, MDL_IDENT))
{
globalErrorStream() << "LoadMDLImage: data has wrong ident\n";
return 0;
}
PointerInputStream inputStream(buffer);
inputStream.seek(4 + 4 + 12 + 12 + 4 + 12);
//int numskins =
istream_read_int32_le(inputStream);
int skinwidth = istream_read_int32_le(inputStream);
int skinheight = istream_read_int32_le(inputStream);
inputStream.seek(4 + 4 + 4 + 4 + 4 + 4);
switch(istream_read_int32_le(inputStream))
{
case MDL_SKIN_SINGLE:
break;
case MDL_SKIN_GROUP:
int numskins = istream_read_int32_le(inputStream);
inputStream.seek(numskins * 4);
break;
}
RGBAImage* image = new RGBAImage(skinwidth, skinheight);
unsigned char* pRGBA = image->getRGBAPixels();
for(int i=0; i<(skinheight); i++)
{
for(int j=0; j<(skinwidth); j++)
{
byte index = istream_read_byte(inputStream);
*pRGBA++ = mdl_palette[index * 3 + 0];
*pRGBA++ = mdl_palette[index * 3 + 1];
*pRGBA++ = mdl_palette[index * 3 + 2];
*pRGBA++ = 255;
}
}
return image;
}
Image* LoadMDLImage(ArchiveFile& file)
{
ScopedArchiveBuffer buffer(file);
return LoadMDLImageBuff( buffer.buffer );
}
void MDLImage_Destroy(byte* pic)
{
free(pic);
}

View File

@@ -0,0 +1,30 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MDLIMAGE_H)
#define INCLUDED_MDLIMAGE_H
class Image;
class ArchiveFile;
Image* LoadMDLImage(ArchiveFile& file);
#endif

View File

@@ -0,0 +1,23 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mdlnormals.h"

View File

@@ -0,0 +1,191 @@
/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
typedef const float mdlNormal_t[3];
typedef const mdlNormal_t mdlNormals_t[162];
const mdlNormals_t g_mdl_normals = {
{-0.525731f, 0.000000f, 0.850651f, },
{-0.442863f, 0.238856f, 0.864188f, },
{-0.295242f, 0.000000f, 0.955423f, },
{-0.309017f, 0.500000f, 0.809017f, },
{-0.162460f, 0.262866f, 0.951056f, },
{ 0.000000f, 0.000000f, 1.000000f, },
{ 0.000000f, 0.850651f, 0.525731f, },
{-0.147621f, 0.716567f, 0.681718f, },
{ 0.147621f, 0.716567f, 0.681718f, },
{ 0.000000f, 0.525731f, 0.850651f, },
{ 0.309017f, 0.500000f, 0.809017f, },
{ 0.525731f, 0.000000f, 0.850651f, },
{ 0.295242f, 0.000000f, 0.955423f, },
{ 0.442863f, 0.238856f, 0.864188f, },
{ 0.162460f, 0.262866f, 0.951056f, },
{-0.681718f, 0.147621f, 0.716567f, },
{-0.809017f, 0.309017f, 0.500000f, },
{-0.587785f, 0.425325f, 0.688191f, },
{-0.850651f, 0.525731f, 0.000000f, },
{-0.864188f, 0.442863f, 0.238856f, },
{-0.716567f, 0.681718f, 0.147621f, },
{-0.688191f, 0.587785f, 0.425325f, },
{-0.500000f, 0.809017f, 0.309017f, },
{-0.238856f, 0.864188f, 0.442863f, },
{-0.425325f, 0.688191f, 0.587785f, },
{-0.716567f, 0.681718f,-0.147621f, },
{-0.500000f, 0.809017f,-0.309017f, },
{-0.525731f, 0.850651f, 0.000000f, },
{ 0.000000f, 0.850651f,-0.525731f, },
{-0.238856f, 0.864188f,-0.442863f, },
{ 0.000000f, 0.955423f,-0.295242f, },
{-0.262866f, 0.951056f,-0.162460f, },
{ 0.000000f, 1.000000f, 0.000000f, },
{ 0.000000f, 0.955423f, 0.295242f, },
{-0.262866f, 0.951056f, 0.162460f, },
{ 0.238856f, 0.864188f, 0.442863f, },
{ 0.262866f, 0.951056f, 0.162460f, },
{ 0.500000f, 0.809017f, 0.309017f, },
{ 0.238856f, 0.864188f,-0.442863f, },
{ 0.262866f, 0.951056f,-0.162460f, },
{ 0.500000f, 0.809017f,-0.309017f, },
{ 0.850651f, 0.525731f, 0.000000f, },
{ 0.716567f, 0.681718f, 0.147621f, },
{ 0.716567f, 0.681718f,-0.147621f, },
{ 0.525731f, 0.850651f, 0.000000f, },
{ 0.425325f, 0.688191f, 0.587785f, },
{ 0.864188f, 0.442863f, 0.238856f, },
{ 0.688191f, 0.587785f, 0.425325f, },
{ 0.809017f, 0.309017f, 0.500000f, },
{ 0.681718f, 0.147621f, 0.716567f, },
{ 0.587785f, 0.425325f, 0.688191f, },
{ 0.955423f, 0.295242f, 0.000000f, },
{ 1.000000f, 0.000000f, 0.000000f, },
{ 0.951056f, 0.162460f, 0.262866f, },
{ 0.850651f,-0.525731f, 0.000000f, },
{ 0.955423f,-0.295242f, 0.000000f, },
{ 0.864188f,-0.442863f, 0.238856f, },
{ 0.951056f,-0.162460f, 0.262866f, },
{ 0.809017f,-0.309017f, 0.500000f, },
{ 0.681718f,-0.147621f, 0.716567f, },
{ 0.850651f, 0.000000f, 0.525731f, },
{ 0.864188f, 0.442863f,-0.238856f, },
{ 0.809017f, 0.309017f,-0.500000f, },
{ 0.951056f, 0.162460f,-0.262866f, },
{ 0.525731f, 0.000000f,-0.850651f, },
{ 0.681718f, 0.147621f,-0.716567f, },
{ 0.681718f,-0.147621f,-0.716567f, },
{ 0.850651f, 0.000000f,-0.525731f, },
{ 0.809017f,-0.309017f,-0.500000f, },
{ 0.864188f,-0.442863f,-0.238856f, },
{ 0.951056f,-0.162460f,-0.262866f, },
{ 0.147621f, 0.716567f,-0.681718f, },
{ 0.309017f, 0.500000f,-0.809017f, },
{ 0.425325f, 0.688191f,-0.587785f, },
{ 0.442863f, 0.238856f,-0.864188f, },
{ 0.587785f, 0.425325f,-0.688191f, },
{ 0.688191f, 0.587785f,-0.425325f, },
{-0.147621f, 0.716567f,-0.681718f, },
{-0.309017f, 0.500000f,-0.809017f, },
{ 0.000000f, 0.525731f,-0.850651f, },
{-0.525731f, 0.000000f,-0.850651f, },
{-0.442863f, 0.238856f,-0.864188f, },
{-0.295242f, 0.000000f,-0.955423f, },
{-0.162460f, 0.262866f,-0.951056f, },
{ 0.000000f, 0.000000f,-1.000000f, },
{ 0.295242f, 0.000000f,-0.955423f, },
{ 0.162460f, 0.262866f,-0.951056f, },
{-0.442863f,-0.238856f,-0.864188f, },
{-0.309017f,-0.500000f,-0.809017f, },
{-0.162460f,-0.262866f,-0.951056f, },
{ 0.000000f,-0.850651f,-0.525731f, },
{-0.147621f,-0.716567f,-0.681718f, },
{ 0.147621f,-0.716567f,-0.681718f, },
{ 0.000000f,-0.525731f,-0.850651f, },
{ 0.309017f,-0.500000f,-0.809017f, },
{ 0.442863f,-0.238856f,-0.864188f, },
{ 0.162460f,-0.262866f,-0.951056f, },
{ 0.238856f,-0.864188f,-0.442863f, },
{ 0.500000f,-0.809017f,-0.309017f, },
{ 0.425325f,-0.688191f,-0.587785f, },
{ 0.716567f,-0.681718f,-0.147621f, },
{ 0.688191f,-0.587785f,-0.425325f, },
{ 0.587785f,-0.425325f,-0.688191f, },
{ 0.000000f,-0.955423f,-0.295242f, },
{ 0.000000f,-1.000000f, 0.000000f, },
{ 0.262866f,-0.951056f,-0.162460f, },
{ 0.000000f,-0.850651f, 0.525731f, },
{ 0.000000f,-0.955423f, 0.295242f, },
{ 0.238856f,-0.864188f, 0.442863f, },
{ 0.262866f,-0.951056f, 0.162460f, },
{ 0.500000f,-0.809017f, 0.309017f, },
{ 0.716567f,-0.681718f, 0.147621f, },
{ 0.525731f,-0.850651f, 0.000000f, },
{-0.238856f,-0.864188f,-0.442863f, },
{-0.500000f,-0.809017f,-0.309017f, },
{-0.262866f,-0.951056f,-0.162460f, },
{-0.850651f,-0.525731f, 0.000000f, },
{-0.716567f,-0.681718f,-0.147621f, },
{-0.716567f,-0.681718f, 0.147621f, },
{-0.525731f,-0.850651f, 0.000000f, },
{-0.500000f,-0.809017f, 0.309017f, },
{-0.238856f,-0.864188f, 0.442863f, },
{-0.262866f,-0.951056f, 0.162460f, },
{-0.864188f,-0.442863f, 0.238856f, },
{-0.809017f,-0.309017f, 0.500000f, },
{-0.688191f,-0.587785f, 0.425325f, },
{-0.681718f,-0.147621f, 0.716567f, },
{-0.442863f,-0.238856f, 0.864188f, },
{-0.587785f,-0.425325f, 0.688191f, },
{-0.309017f,-0.500000f, 0.809017f, },
{-0.147621f,-0.716567f, 0.681718f, },
{-0.425325f,-0.688191f, 0.587785f, },
{-0.162460f,-0.262866f, 0.951056f, },
{ 0.442863f,-0.238856f, 0.864188f, },
{ 0.162460f,-0.262866f, 0.951056f, },
{ 0.309017f,-0.500000f, 0.809017f, },
{ 0.147621f,-0.716567f, 0.681718f, },
{ 0.000000f,-0.525731f, 0.850651f, },
{ 0.425325f,-0.688191f, 0.587785f, },
{ 0.587785f,-0.425325f, 0.688191f, },
{ 0.688191f,-0.587785f, 0.425325f, },
{-0.955423f, 0.295242f, 0.000000f, },
{-0.951056f, 0.162460f, 0.262866f, },
{-1.000000f, 0.000000f, 0.000000f, },
{-0.850651f, 0.000000f, 0.525731f, },
{-0.955423f,-0.295242f, 0.000000f, },
{-0.951056f,-0.162460f, 0.262866f, },
{-0.864188f, 0.442863f,-0.238856f, },
{-0.951056f, 0.162460f,-0.262866f, },
{-0.809017f, 0.309017f,-0.500000f, },
{-0.864188f,-0.442863f,-0.238856f, },
{-0.951056f,-0.162460f,-0.262866f, },
{-0.809017f,-0.309017f,-0.500000f, },
{-0.681718f, 0.147621f,-0.716567f, },
{-0.681718f,-0.147621f,-0.716567f, },
{-0.850651f, 0.000000f,-0.525731f, },
{-0.688191f, 0.587785f,-0.425325f, },
{-0.587785f, 0.425325f,-0.688191f, },
{-0.425325f, 0.688191f,-0.587785f, },
{-0.425325f,-0.688191f,-0.587785f, },
{-0.587785f,-0.425325f,-0.688191f, },
{-0.688191f,-0.587785f,-0.425325f, },
};

View File

@@ -0,0 +1,23 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "model.h"

643
plugins/md3model/model.h Normal file
View File

@@ -0,0 +1,643 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_MODEL_H)
#define INCLUDED_MODEL_H
#include "cullable.h"
#include "renderable.h"
#include "selectable.h"
#include "modelskin.h"
#include "math/frustum.h"
#include "string/string.h"
#include "generic/static.h"
#include "stream/stringstream.h"
#include "os/path.h"
#include "scenelib.h"
#include "instancelib.h"
#include "transformlib.h"
#include "traverselib.h"
#include "render.h"
class VectorLightList : public LightList
{
typedef std::vector<const RendererLight*> Lights;
Lights m_lights;
public:
void addLight(const RendererLight& light)
{
m_lights.push_back(&light);
}
void clear()
{
m_lights.clear();
}
void evaluateLights() const
{
}
void lightsChanged() const
{
}
void forEachLight(const RendererLightCallback& callback) const
{
for(Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i)
{
callback(*(*i));
}
}
};
inline VertexPointer vertexpointer_arbitrarymeshvertex(const ArbitraryMeshVertex* array)
{
return VertexPointer(VertexPointer::pointer(&array->vertex), sizeof(ArbitraryMeshVertex));
}
inline void parseTextureName(CopiedString& name, const char* token)
{
StringOutputStream cleaned(256);
cleaned << PathCleaned(token);
name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
}
// generic renderable triangle surface
class Surface :
public OpenGLRenderable
{
public:
typedef VertexBuffer<ArbitraryMeshVertex> vertices_t;
typedef IndexBuffer indices_t;
private:
AABB m_aabb_local;
CopiedString m_shader;
Shader* m_state;
vertices_t m_vertices;
indices_t m_indices;
void CaptureShader()
{
m_state = GlobalShaderCache().capture(m_shader.c_str());
}
void ReleaseShader()
{
GlobalShaderCache().release(m_shader.c_str());
}
public:
Surface()
: m_shader(""), m_state(0)
{
CaptureShader();
}
~Surface()
{
ReleaseShader();
}
vertices_t& vertices()
{
return m_vertices;
}
indices_t& indices()
{
return m_indices;
}
void setShader(const char* name)
{
ReleaseShader();
parseTextureName(m_shader, name);
CaptureShader();
}
const char* getShader() const
{
return m_shader.c_str();
}
Shader* getState() const
{
return m_state;
}
void updateAABB()
{
m_aabb_local = AABB();
for(vertices_t::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
aabb_extend_by_point_safe(m_aabb_local, reinterpret_cast<const Vector3&>((*i).vertex));
for(Surface::indices_t::iterator i = m_indices.begin(); i != m_indices.end(); i += 3)
{
ArbitraryMeshVertex& a = m_vertices[*(i + 0)];
ArbitraryMeshVertex& b = m_vertices[*(i + 1)];
ArbitraryMeshVertex& c = m_vertices[*(i + 2)];
ArbitraryMeshTriangle_sumTangents(a, b, c);
}
for(Surface::vertices_t::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
{
vector3_normalise(reinterpret_cast<Vector3&>((*i).tangent));
vector3_normalise(reinterpret_cast<Vector3&>((*i).bitangent));
}
}
void render(RenderStateFlags state) const
{
#if 1
if((state & RENDER_BUMP) != 0)
{
if(GlobalShaderCache().useShaderLanguage())
{
glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent);
glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->bitangent);
}
else
{
glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent);
glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->bitangent);
}
}
else
{
glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
glTexCoordPointer(2, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
}
glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->vertex);
glDrawElements(GL_TRIANGLES, GLsizei(m_indices.size()), RenderIndexTypeID, m_indices.data());
#else
glBegin(GL_TRIANGLES);
for(unsigned int i = 0; i < m_indices.size(); ++i)
{
glTexCoord2fv(&m_vertices[m_indices[i]].texcoord.s);
glNormal3fv(&m_vertices[m_indices[i]].normal.x);
glVertex3fv(&m_vertices[m_indices[i]].vertex.x);
}
glEnd();
#endif
#if defined(_DEBUG)
glBegin(GL_LINES);
for(VertexBuffer<ArbitraryMeshVertex>::const_iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
{
Vector3 normal = vector3_added(vertex3f_to_vector3((*i).vertex), vector3_scaled(normal3f_to_vector3((*i).normal), 8));
glVertex3fv(vertex3f_to_array((*i).vertex));
glVertex3fv(vector3_to_array(normal));
}
glEnd();
#endif
}
VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
{
return test.TestAABB(m_aabb_local, localToWorld);
}
const AABB& localAABB() const
{
return m_aabb_local;
}
void render(Renderer& renderer, const Matrix4& localToWorld, Shader* state) const
{
renderer.SetState(state, Renderer::eFullMaterials);
renderer.addRenderable(*this, localToWorld);
}
void render(Renderer& renderer, const Matrix4& localToWorld) const
{
render(renderer, localToWorld, m_state);
}
void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
{
test.BeginMesh(localToWorld);
SelectionIntersection best;
test.TestTriangles(
vertexpointer_arbitrarymeshvertex(m_vertices.data()),
IndexPointer(m_indices.data(), IndexPointer::index_type(m_indices.size())),
best
);
if(best.valid())
{
selector.addIntersection(best);
}
}
};
// generic model node
class Model :
public Cullable,
public Bounded
{
typedef std::vector<Surface*> surfaces_t;
surfaces_t m_surfaces;
AABB m_aabb_local;
public:
Callback m_lightsChanged;
~Model()
{
for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
{
delete *i;
}
}
typedef surfaces_t::const_iterator const_iterator;
const_iterator begin() const
{
return m_surfaces.begin();
}
const_iterator end() const
{
return m_surfaces.end();
}
std::size_t size() const
{
return m_surfaces.size();
}
Surface& newSurface()
{
m_surfaces.push_back(new Surface);
return *m_surfaces.back();
}
void updateAABB()
{
m_aabb_local = AABB();
for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
{
aabb_extend_by_aabb_safe(m_aabb_local, (*i)->localAABB());
}
}
VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
{
return test.TestAABB(m_aabb_local, localToWorld);
}
virtual const AABB& localAABB() const
{
return m_aabb_local;
}
void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
{
for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
{
if((*i)->intersectVolume(test.getVolume(), localToWorld) != c_volumeOutside)
{
(*i)->testSelect(selector, test, localToWorld);
}
}
}
};
inline void Surface_addLight(const Surface& surface, VectorLightList& lights, const Matrix4& localToWorld, const RendererLight& light)
{
if(light.testAABB(aabb_for_oriented_aabb(surface.localAABB(), localToWorld)))
{
lights.addLight(light);
}
}
class ModelInstance :
public scene::Instance,
public Renderable,
public SelectionTestable,
public LightCullable,
public SkinnedModel
{
class TypeCasts
{
InstanceTypeCastTable m_casts;
public:
TypeCasts()
{
InstanceContainedCast<ModelInstance, Bounded>::install(m_casts);
InstanceContainedCast<ModelInstance, Cullable>::install(m_casts);
InstanceStaticCast<ModelInstance, Renderable>::install(m_casts);
InstanceStaticCast<ModelInstance, SelectionTestable>::install(m_casts);
InstanceStaticCast<ModelInstance, SkinnedModel>::install(m_casts);
}
InstanceTypeCastTable& get()
{
return m_casts;
}
};
Model& m_model;
const LightList* m_lightList;
typedef Array<VectorLightList> SurfaceLightLists;
SurfaceLightLists m_surfaceLightLists;
class Remap
{
public:
CopiedString first;
Shader* second;
Remap() : second(0)
{
}
};
typedef Array<Remap> SurfaceRemaps;
SurfaceRemaps m_skins;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
Bounded& get(NullType<Bounded>)
{
return m_model;
}
Cullable& get(NullType<Cullable>)
{
return m_model;
}
void lightsChanged()
{
m_lightList->lightsChanged();
}
typedef MemberCaller<ModelInstance, &ModelInstance::lightsChanged> LightsChangedCaller;
void constructRemaps()
{
ModelSkin* skin = NodeTypeCast<ModelSkin>::cast(path().parent());
if(skin != 0 && skin->realised())
{
SurfaceRemaps::iterator j = m_skins.begin();
for(Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i, ++j)
{
const char* remap = skin->getRemap((*i)->getShader());
if(!string_empty(remap))
{
(*j).first = remap;
(*j).second = GlobalShaderCache().capture(remap);
}
else
{
(*j).second = 0;
}
}
SceneChangeNotify();
}
}
void destroyRemaps()
{
for(SurfaceRemaps::iterator i = m_skins.begin(); i != m_skins.end(); ++i)
{
if((*i).second != 0)
{
GlobalShaderCache().release((*i).first.c_str());
(*i).second = 0;
}
}
}
void skinChanged()
{
ASSERT_MESSAGE(m_skins.size() == m_model.size(), "ERROR");
destroyRemaps();
constructRemaps();
}
ModelInstance(const scene::Path& path, scene::Instance* parent, Model& model) :
Instance(path, parent, this, StaticTypeCasts::instance().get()),
m_model(model),
m_surfaceLightLists(m_model.size()),
m_skins(m_model.size())
{
m_lightList = &GlobalShaderCache().attach(*this);
m_model.m_lightsChanged = LightsChangedCaller(*this);
Instance::setTransformChangedCallback(LightsChangedCaller(*this));
constructRemaps();
}
~ModelInstance()
{
destroyRemaps();
Instance::setTransformChangedCallback(Callback());
m_model.m_lightsChanged = Callback();
GlobalShaderCache().detach(*this);
}
void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
{
SurfaceLightLists::const_iterator j = m_surfaceLightLists.begin();
SurfaceRemaps::const_iterator k = m_skins.begin();
for(Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i, ++j, ++k)
{
if((*i)->intersectVolume(volume, localToWorld) != c_volumeOutside)
{
renderer.setLights(*j);
(*i)->render(renderer, localToWorld, (*k).second != 0 ? (*k).second : (*i)->getState());
}
}
}
void renderSolid(Renderer& renderer, const VolumeTest& volume) const
{
m_lightList->evaluateLights();
render(renderer, volume, Instance::localToWorld());
}
void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
{
renderSolid(renderer, volume);
}
void testSelect(Selector& selector, SelectionTest& test)
{
m_model.testSelect(selector, test, Instance::localToWorld());
}
bool testLight(const RendererLight& light) const
{
return light.testAABB(worldAABB());
}
void insertLight(const RendererLight& light)
{
const Matrix4& localToWorld = Instance::localToWorld();
SurfaceLightLists::iterator j = m_surfaceLightLists.begin();
for(Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i)
{
Surface_addLight(*(*i), *j++, localToWorld, light);
}
}
void clearLights()
{
for(SurfaceLightLists::iterator i = m_surfaceLightLists.begin(); i != m_surfaceLightLists.end(); ++i)
{
(*i).clear();
}
}
};
class ModelNode : public scene::Node::Symbiot, public scene::Instantiable
{
class TypeCasts
{
NodeTypeCastTable m_casts;
public:
TypeCasts()
{
NodeStaticCast<ModelNode, scene::Instantiable>::install(m_casts);
}
NodeTypeCastTable& get()
{
return m_casts;
}
};
scene::Node m_node;
InstanceSet m_instances;
Model m_model;
public:
typedef LazyStatic<TypeCasts> StaticTypeCasts;
ModelNode() : m_node(this, this, StaticTypeCasts::instance().get())
{
}
Model& model()
{
return m_model;
}
void release()
{
delete this;
}
scene::Node& node()
{
return m_node;
}
scene::Instance* create(const scene::Path& path, scene::Instance* parent)
{
return new ModelInstance(path, parent, m_model);
}
void forEachInstance(const scene::Instantiable::Visitor& visitor)
{
m_instances.forEachInstance(visitor);
}
void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
{
m_instances.insert(observer, path, instance);
}
scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
{
return m_instances.erase(observer, path);
}
};
inline void Surface_constructQuad(Surface& surface, const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d, const Vector3& normal)
{
surface.vertices().push_back(
ArbitraryMeshVertex(
vertex3f_for_vector3(a),
normal3f_for_vector3(normal),
texcoord2f_from_array(aabb_texcoord_topleft)
)
);
surface.vertices().push_back(
ArbitraryMeshVertex(
vertex3f_for_vector3(b),
normal3f_for_vector3(normal),
texcoord2f_from_array(aabb_texcoord_topright)
)
);
surface.vertices().push_back(
ArbitraryMeshVertex(
vertex3f_for_vector3(c),
normal3f_for_vector3(normal),
texcoord2f_from_array(aabb_texcoord_botright)
)
);
surface.vertices().push_back(
ArbitraryMeshVertex(
vertex3f_for_vector3(d),
normal3f_for_vector3(normal),
texcoord2f_from_array(aabb_texcoord_botleft)
)
);
}
inline void Model_constructNull(Model& model)
{
Surface& surface = model.newSurface();
AABB aabb(Vector3(0, 0, 0), Vector3(8, 8, 8));
Vector3 points[8];
aabb_corners(aabb, points);
surface.vertices().reserve(24);
Surface_constructQuad(surface, points[2], points[1], points[5], points[6], aabb_normals[0]);
Surface_constructQuad(surface, points[1], points[0], points[4], points[5], aabb_normals[1]);
Surface_constructQuad(surface, points[0], points[1], points[2], points[3], aabb_normals[2]);
Surface_constructQuad(surface, points[0], points[3], points[7], points[4], aabb_normals[3]);
Surface_constructQuad(surface, points[3], points[2], points[6], points[7], aabb_normals[4]);
Surface_constructQuad(surface, points[7], points[6], points[5], points[4], aabb_normals[5]);
surface.indices().reserve(36);
RenderIndex indices[36] = {
0, 1, 2, 0, 2, 3,
4, 5, 6, 4, 6, 7,
8, 9, 10, 8, 10, 11,
12, 13, 14, 12, 14, 15,
16, 17, 18, 16, 18, 19,
20, 21, 22, 10, 22, 23,
};
for(RenderIndex* i = indices; i != indices+(sizeof(indices)/sizeof(RenderIndex)); ++i)
{
surface.indices().insert(*i);
}
surface.setShader("");
surface.updateAABB();
model.updateAABB();
}
#endif

View File

@@ -0,0 +1,7 @@
; modelmd3.def : Declares the module parameters for the DLL.
LIBRARY "MODELMD3"
EXPORTS
; Explicit exports can go here
Radiant_RegisterModules @1

View File

@@ -0,0 +1,270 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="modelmd3"
ProjectGUID="{C2A5530D-C2DB-4503-A651-4B92AEC5FE74}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;;&quot;../../../gtk2-2.4/include/glib-2.0&quot;;&quot;../../../gtk2-2.4/lib/glib-2.0/include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MODELMD3_EXPORTS"
StringPooling="TRUE"
MinimalRebuild="TRUE"
ExceptionHandling="FALSE"
BasicRuntimeChecks="0"
RuntimeLibrary="3"
BufferSecurityCheck="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
BrowseInformation="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
DisableSpecificWarnings="4610;4510;4512;4505;4100;4127"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib"
OutputFile="$(OutDir)/modelmd3.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;../../../gtk2-2.4/lib&quot;"
IgnoreDefaultLibraryNames="msvcprtd.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/modelmd3.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/modelmd3.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OptimizeForWindowsApplication="FALSE"
AdditionalIncludeDirectories="../../include;../../libs;&quot;../../../STLPort-4.6/stlport&quot;;&quot;../../../gtk2-2.4/include/glib-2.0&quot;;&quot;../../../gtk2-2.4/lib/glib-2.0/include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MODELMD3_EXPORTS"
StringPooling="TRUE"
ExceptionHandling="FALSE"
RuntimeLibrary="2"
BufferSecurityCheck="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"
DisableSpecificWarnings="4610;4510;4512;4505;4100;4127"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib"
OutputFile="$(OutDir)/modelmd3.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;../../../gtk2-2.4/lib&quot;"
IgnoreDefaultLibraryNames="msvcprt.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/modelmd3.lib"
TargetMachine="1"
FixedBaseAddress="0"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)install\modules&quot;
copy &quot;$(TargetDir)$(TargetName).pdb&quot; &quot;$(SolutionDir)install\modules&quot;"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="src"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\plugin.cpp">
</File>
<File
RelativePath=".\plugin.h">
</File>
<Filter
Name="modules"
Filter="">
<File
RelativePath=".\md2.cpp">
</File>
<File
RelativePath=".\md2.h">
</File>
<File
RelativePath=".\md3.cpp">
</File>
<File
RelativePath=".\md3.h">
</File>
<File
RelativePath=".\md5.cpp">
</File>
<File
RelativePath=".\md5.h">
</File>
<File
RelativePath=".\mdc.cpp">
</File>
<File
RelativePath=".\mdc.h">
</File>
<File
RelativePath=".\mdl.cpp">
</File>
<File
RelativePath=".\mdl.h">
</File>
<File
RelativePath=".\mdlimage.cpp">
</File>
<File
RelativePath=".\mdlimage.h">
</File>
</Filter>
<Filter
Name="components"
Filter="">
<File
RelativePath=".\ident.h">
</File>
<File
RelativePath=".\md3normals.cpp">
</File>
<File
RelativePath=".\md3normals.h">
</File>
<File
RelativePath=".\mdlformat.cpp">
</File>
<File
RelativePath=".\mdlformat.h">
</File>
<File
RelativePath=".\mdlnormals.cpp">
</File>
<File
RelativePath=".\mdlnormals.h">
</File>
<File
RelativePath=".\model.cpp">
</File>
<File
RelativePath=".\model.h">
</File>
</Filter>
</Filter>
<File
RelativePath="..\..\debug.py">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)debug.py&quot;"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetName).pdb&quot;"
Outputs="&quot;$(TargetDir)$(TargetName).pdb&quot;"/>
</FileConfiguration>
</File>
<File
RelativePath=".\modelmd3.def">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="python &quot;$(SolutionDir)touch.py&quot; &quot;$(TargetPath)&quot;
"
AdditionalDependencies="&quot;$(SolutionDir)install\modules\$(TargetFileName)&quot;"
Outputs="&quot;$(TargetPath)&quot;"/>
</FileConfiguration>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

250
plugins/md3model/plugin.cpp Normal file
View File

@@ -0,0 +1,250 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "plugin.h"
#include "iscenegraph.h"
#include "irender.h"
#include "iselection.h"
#include "iimage.h"
#include "imodel.h"
#include "igl.h"
#include "ifilesystem.h"
#include "iundo.h"
#include "ifiletypes.h"
#include "iscriplib.h"
#include "modulesystem/singletonmodule.h"
#include "typesystem.h"
#include "md3.h"
#include "mdl.h"
#include "md2.h"
#include "mdc.h"
#include "mdlimage.h"
#include "md5.h"
class MD3ModelLoader : public ModelLoader
{
public:
scene::Node& loadModel(ArchiveFile& file)
{
return loadMD3Model(file);
}
};
class ModelDependencies :
public GlobalFileSystemModuleRef,
public GlobalOpenGLModuleRef,
public GlobalUndoModuleRef,
public GlobalSceneGraphModuleRef,
public GlobalShaderCacheModuleRef,
public GlobalSelectionModuleRef,
public GlobalFiletypesModuleRef
{
};
class ModelMD3API : public TypeSystemRef
{
MD3ModelLoader m_modelmd3;
public:
typedef ModelLoader Type;
STRING_CONSTANT(Name, "md3");
ModelMD3API()
{
GlobalFiletypesModule::getTable().addType(Type::Name(), Name(), filetype_t("md3 models", "*.md3"));
}
ModelLoader* getTable()
{
return &m_modelmd3;
}
};
typedef SingletonModule<ModelMD3API, ModelDependencies> ModelMD3Module;
ModelMD3Module g_ModelMD3Module;
class MD2ModelLoader : public ModelLoader
{
public:
scene::Node& loadModel(ArchiveFile& file)
{
return loadMD2Model(file);
}
};
class ModelMD2API : public TypeSystemRef
{
MD2ModelLoader m_modelmd2;
public:
typedef ModelLoader Type;
STRING_CONSTANT(Name, "md2");
ModelMD2API()
{
GlobalFiletypesModule::getTable().addType(Type::Name(), Name(), filetype_t("md2 models", "*.md2"));
}
ModelLoader* getTable()
{
return &m_modelmd2;
}
};
typedef SingletonModule<ModelMD2API, ModelDependencies> ModelMD2Module;
ModelMD2Module g_ModelMD2Module;
class MDLModelLoader : public ModelLoader
{
public:
scene::Node& loadModel(ArchiveFile& file)
{
return loadMDLModel(file);
}
};
class ModelMDLAPI : public TypeSystemRef
{
MDLModelLoader m_modelmdl;
public:
typedef ModelLoader Type;
STRING_CONSTANT(Name, "mdl");
ModelMDLAPI()
{
GlobalFiletypesModule::getTable().addType(Type::Name(), Name(), filetype_t("mdl models", "*.mdl"));
}
ModelLoader* getTable()
{
return &m_modelmdl;
}
};
typedef SingletonModule<ModelMDLAPI, ModelDependencies> ModelMDLModule;
ModelMDLModule g_ModelMDLModule;
class MDCModelLoader : public ModelLoader
{
public:
scene::Node& loadModel(ArchiveFile& file)
{
return loadMDCModel(file);
}
};
class ModelMDCAPI : public TypeSystemRef
{
MDCModelLoader m_modelmdc;
public:
typedef ModelLoader Type;
STRING_CONSTANT(Name, "mdc");
ModelMDCAPI()
{
GlobalFiletypesModule::getTable().addType(Type::Name(), Name(), filetype_t("mdc models", "*.mdc"));
}
ModelLoader* getTable()
{
return &m_modelmdc;
}
};
typedef SingletonModule<ModelMDCAPI, ModelDependencies> ModelMDCModule;
ModelMDCModule g_ModelMDCModule;
class ImageMDLAPI
{
_QERPlugImageTable m_imagemdl;
public:
typedef _QERPlugImageTable Type;
STRING_CONSTANT(Name, "mdl");
ImageMDLAPI()
{
m_imagemdl.loadImage = &LoadMDLImage;
}
_QERPlugImageTable* getTable()
{
return &m_imagemdl;
}
};
typedef SingletonModule<ImageMDLAPI, GlobalFileSystemModuleRef> ImageMDLModule;
ImageMDLModule g_ImageMDLModule;
class MD5ModelLoader : public ModelLoader
{
public:
scene::Node& loadModel(ArchiveFile& file)
{
return loadMD5Model(file);
}
};
class ModelMD5Dependencies : public ModelDependencies, public GlobalScripLibModuleRef
{
};
class ModelMD5API : public TypeSystemRef
{
MD5ModelLoader m_modelmd5;
public:
typedef ModelLoader Type;
STRING_CONSTANT(Name, "md5mesh");
ModelMD5API()
{
GlobalFiletypesModule::getTable().addType(Type::Name(), Name(), filetype_t("md5 meshes", "*.md5mesh"));
}
ModelLoader* getTable()
{
return &m_modelmd5;
}
};
typedef SingletonModule<ModelMD5API, ModelMD5Dependencies> ModelMD5Module;
ModelMD5Module g_ModelMD5Module;
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules(ModuleServer& server)
{
GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
GlobalModuleServer::instance().set(server);
g_ModelMD3Module.selfRegister();
g_ModelMD2Module.selfRegister();
g_ModelMDLModule.selfRegister();
g_ModelMDCModule.selfRegister();
g_ImageMDLModule.selfRegister();
g_ModelMD5Module.selfRegister();
}

25
plugins/md3model/plugin.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if !defined(INCLUDED_PLUGIN_H)
#define INCLUDED_PLUGIN_H
#endif