root/OpenSceneGraph/branches/OpenSceneGraph-2.8/src/osgPlugins/bsp/VBSPReader.cpp @ 11238

Revision 11238, 38.5 kB (checked in by paulmartz, 4 years ago)

2.8 branch: Minor bug fixes for ac and 3dc plugins. Merges these revisions from trunk: 10010, 10758, and 11175.

  • Property svn:mergeinfo set to
    /OpenSceneGraph/branches/OpenSceneGraph-2.8.2/src/osgPlugins/bsp/VBSPReader.cpp:10664
    /OpenSceneGraph/trunk/src/osgPlugins/bsp/VBSPReader.cpp:9769,9879-9880,9895,9932,10010,10208,10340,10417,10456,10482-10484,10487,10539,10622-10623,10625,10671-10672,10697,10722,10753,10758,10788,10818,10854-10855,10858,10887,10891,10923,10933,11019,11032,11034-11035,11111,11127,11131,11175
Line 
1#include <osg/BlendFunc>
2#include <osg/BoundingSphere>
3#include <osg/Geometry>
4#include <osg/Group>
5#include <osg/Object>
6#include <osg/Material>
7#include <osg/Math>
8#include <osg/MatrixTransform>
9#include <osg/Node>
10#include <osg/Notify>
11#include <osg/Quat>
12#include <osg/StateSet>
13#include <osg/Texture1D>
14#include <osg/Texture2D>
15#include <osg/Texture3D>
16#include <osgDB/Registry>
17#include <osgDB/FileUtils>
18#include <osgDB/ReadFile>
19#include <osg/io_utils>
20#include <iostream>
21#include <string.h>
22
23#include "VBSPReader.h"
24#include "VBSPEntity.h"
25
26
27using namespace bsp;
28using namespace osg;
29using namespace osgDB;
30
31
32// strcasecmp for MSVC
33#ifdef _MSC_VER
34   #define strcasecmp  _stricmp
35#endif
36
37
38VBSPReader::VBSPReader()
39{
40    // Start with no root node
41    root_node = NULL;
42
43    // Create the map data object
44    bsp_data = new VBSPData();
45
46    // No string table yet
47    texdata_string = NULL;
48    texdata_string_table = NULL;
49    num_texdata_string_table_entries = 0;
50}
51
52
53VBSPReader::~VBSPReader()
54{
55    // Clean up the texdata strings and such
56    delete [] texdata_string;
57    delete [] texdata_string_table;
58}
59
60
61void VBSPReader::processEntities(std::istream & str, int offset,
62                                 int length)
63{
64    char *          entities;
65    char *          startPtr;
66    char *          endPtr;
67    int             numEntities;
68    int             i;
69    std::string     entityStr;
70    size_t          entityLen;
71
72    // Create the string
73    entities = new char[length];
74    memset(entities, 0, length * sizeof(char));
75
76    // Seek to the Entities lump
77    str.seekg(offset);
78
79    // Read the entities string
80    str.read((char *) entities, sizeof(char) * length);
81
82    // Count the number of entities
83    startPtr = entities;
84    endPtr = strchr(entities, '}');
85    numEntities = 0;
86    while ((startPtr != NULL) && (endPtr != NULL))
87    {
88        // Increment the count
89        numEntities++;
90
91        // Advance the pointers
92        startPtr = strchr(endPtr, '{');
93        if (startPtr != NULL)
94            endPtr = strchr(startPtr, '}');
95    }
96
97    // Parse the entities
98    startPtr = entities;
99    endPtr = strchr(entities, '}');
100    for (i = 0; i < numEntities; i++)
101    {
102        // Get the length of this entity
103        entityLen = endPtr - startPtr + 1;
104
105        // Create the entity list entry and copy the entity information
106        entityStr = std::string(startPtr, entityLen);
107        bsp_data->addEntity(entityStr);
108
109        // Advance the pointers
110        startPtr = strchr(endPtr, '{');
111        if (startPtr != NULL)
112            endPtr = strchr(startPtr, '}');
113    }
114
115    // Free up the original entities string
116    delete [] entities;
117}
118
119
120void VBSPReader::processModels(std::istream & str, int offset, int length)
121{
122    int       numModels;
123    int       i;
124    Model *   models;
125
126    // Calculate the number of models
127    numModels = length / sizeof(Model);
128
129    // Seek to the Models lump
130    str.seekg(offset);
131
132    // Read the models
133    models = new Model[numModels];
134    str.read((char *) models, sizeof(Model) * numModels);
135
136    // Add the models to the model list
137    for (i = 0; i < numModels; i++)
138        bsp_data->addModel(models[i]);
139
140    // Clean up
141    delete [] models;
142}
143
144
145void VBSPReader::processPlanes(std::istream & str, int offset, int length)
146{
147    int       numPlanes;
148    int       i;
149    Plane *   planes;
150
151    // Calculate the number of planes
152    numPlanes = length / sizeof(Plane);
153
154    // Seek to the Planes lump
155    str.seekg(offset);
156
157    // Read the planes
158    planes = new Plane[numPlanes];
159    str.read((char *) planes, sizeof(Plane) * numPlanes);
160
161    // Add the planes to the plane list
162    for (i = 0; i < numPlanes; i++)
163        bsp_data->addPlane(planes[i]);
164
165    // Clean up
166    delete [] planes;
167}
168
169
170void VBSPReader::processVertices(std::istream & str, int offset, int length)
171{
172    int       numVertices;
173    int       i;
174    Vec3f *   vertices;
175
176    // Calculate the number of vertices
177    numVertices = length / 3 / sizeof(float);
178
179    // Seek to the Vertices lump
180    str.seekg(offset);
181
182    // Read the vertex
183    vertices = new Vec3f[numVertices];
184    str.read((char *) vertices, sizeof(Vec3f) * numVertices);
185
186    // Add it the vertices to the list
187    for (i = 0; i < numVertices; i++)
188        bsp_data->addVertex(vertices[i]);
189
190    // Clean up
191    delete [] vertices;
192}
193
194
195void VBSPReader::processEdges(std::istream & str, int offset, int length)
196{
197    int      numEdges;
198    int      i;
199    Edge *   edges;
200
201    // Calculate the number of edges
202    numEdges = length / sizeof(Edge);
203
204    // Seek to the Edges lump
205    str.seekg(offset);
206
207    // Read the edges
208    edges = new Edge[numEdges];
209    str.read((char *) edges, sizeof(Edge) * numEdges);
210
211    // Add the edges to the edge list
212    for (i = 0; i < numEdges; i++)
213        bsp_data->addEdge(edges[i]);
214
215    // Clean up
216    delete [] edges;
217}
218
219
220void VBSPReader::processSurfEdges(std::istream & str, int offset, int length)
221{
222    int     numSurfEdges;
223    int     i;
224    int *   surfEdges;
225
226    // Calculate the number of edges
227    numSurfEdges = length / sizeof(int);
228
229    // Seek to the SurfEdges lump
230    str.seekg(offset);
231
232    // Read the surface edges
233    surfEdges = new int[numSurfEdges];
234    str.read((char *) surfEdges, sizeof(int) * numSurfEdges);
235
236    // Add the surface edges to the surface edge list
237    for (i = 0; i < numSurfEdges; i++)
238        bsp_data->addSurfaceEdge(surfEdges[i]);
239
240    // Clean up
241    delete [] surfEdges;
242}
243
244
245void VBSPReader::processFaces(std::istream & str, int offset, int length)
246{
247    int      numFaces;
248    int      i;
249    Face *   faces;
250
251    // Calculate the number of faces
252    numFaces = length / sizeof(Face);
253
254    // Seek to the Faces lump
255    str.seekg(offset);
256
257    // Read the faces
258    faces = new Face[numFaces];
259    str.read((char *) faces, sizeof(Face) * numFaces);
260
261    // Add the faces to the face list
262    for (i = 0; i < numFaces; i++)
263        bsp_data->addFace(faces[i]);
264
265    // Clean up
266    delete [] faces;
267}
268
269
270void VBSPReader::processTexInfo(std::istream & str, int offset, int length)
271{
272    int         numTexInfos;
273    int         i;
274    TexInfo *   texinfos;
275
276    // Calculate the number of texinfos
277    numTexInfos = length / sizeof(TexInfo);
278
279    // Seek to the TexInfo lump
280    str.seekg(offset);
281
282    // Read in the texinfo entries
283    texinfos = new TexInfo[numTexInfos];
284    str.read((char *) texinfos, sizeof(TexInfo) * numTexInfos);
285
286    // Add the texinfo entries to the texinfo list
287    for (i = 0; i < numTexInfos; i++)
288        bsp_data->addTexInfo(texinfos[i]);
289
290    // Clean up
291    delete [] texinfos;
292}
293
294
295void VBSPReader::processTexData(std::istream & str, int offset, int length)
296{
297    int         numTexDatas;
298    int         i;
299    TexData *   texdatas;
300
301    // Calculate the number of texdatas
302    numTexDatas = length / sizeof(TexData);
303
304    // Seek to the TexData lump
305    str.seekg(offset);
306
307    // Read in the texdata entries
308    texdatas = new TexData[numTexDatas];
309    str.read((char *) texdatas, sizeof(TexData) * numTexDatas);
310
311    // Add the texdata entries to the texdata list
312    for (i = 0; i < numTexDatas; i++)
313        bsp_data->addTexData(texdatas[i]);
314
315    // Clean up
316    delete [] texdatas;
317}
318
319
320void VBSPReader::processTexDataStringTable(std::istream & str, int offset,
321                                           int length)
322{
323    int           i;
324    int           index;
325    std::string   texStr;
326
327    // Calculate the number of table entries
328    num_texdata_string_table_entries = length / sizeof(int);
329
330    // Create the texdata string table
331    texdata_string_table = new int[num_texdata_string_table_entries];
332
333    // Seek to the TexDataStringTable lump
334    str.seekg(offset);
335
336    // Read in the texdata_string_table
337    str.read((char *) texdata_string_table,
338             sizeof(int) * num_texdata_string_table_entries);
339
340    // If we have a texdata string loaded, parse the texdata strings now
341    if (texdata_string != NULL)
342    {
343        for (i = 0; i < num_texdata_string_table_entries; i++)
344        {
345            // Add the strings from the string data, using the string table
346            // to index it
347            index = texdata_string_table[i];
348            texStr = std::string(&texdata_string[index]);
349            bsp_data->addTexDataString(texStr);
350        }
351    }
352}
353
354
355void VBSPReader::processTexDataStringData(std::istream & str, int offset,
356                                          int length)
357{
358    int      i;
359    int           index;
360    std::string   texStr;
361
362    // Create the buffer to hold the texdata string
363    texdata_string = new char[length];
364    memset(texdata_string, 0, length * sizeof(char));
365
366    // Seek to the TexDataStringData lump
367    str.seekg(offset);
368
369    // Read the entire texdata string (this string is actually a
370    // NULL-delimited list of strings)
371    str.read((char *) texdata_string, sizeof(char) * length);
372
373    // If we have a string table loaded, parse the texdata strings now
374    // (if not, num_texdata_string_table_entries will be zero and we'll
375    // skip this loop)
376    for (i = 0; i < num_texdata_string_table_entries; i++)
377    {
378        // Add the strings from the string data, using the string table
379        // to index it
380        index = texdata_string_table[i];
381        texStr = std::string(&texdata_string[index]);
382        bsp_data->addTexDataString(texStr);
383    }
384}
385
386
387void VBSPReader::processDispInfo(std::istream & str, int offset, int length)
388{
389    int              numDispInfos;
390    int              i;
391    DisplaceInfo *   dispinfos;
392
393    // Calculate the number of dispinfos
394    numDispInfos = length / sizeof(DisplaceInfo);
395
396    // Seek to the DisplaceInfo lump
397    str.seekg(offset);
398
399    // Read in the dispinfo entries
400    dispinfos = new DisplaceInfo[numDispInfos];
401    str.read((char *) dispinfos, sizeof(DisplaceInfo) * numDispInfos);
402
403    // Add the dispinfo entries to the displace info list
404    for (i = 0; i < numDispInfos; i++)
405        bsp_data->addDispInfo(dispinfos[i]);
406
407    // Clean up
408    delete [] dispinfos;
409}
410
411
412void VBSPReader::processDispVerts(std::istream & str, int offset, int length)
413{
414    int                 numDispVerts;
415    int                 i;
416    DisplacedVertex *   dispverts;
417
418    // Calculate the number of displaced vertices
419    numDispVerts = length / sizeof(DisplacedVertex);
420
421    // Seek to the DispVert lump
422    str.seekg(offset);
423
424    // Read in the displaced vertices
425    dispverts = new DisplacedVertex[numDispVerts];
426    str.read((char *) dispverts, sizeof(DisplacedVertex) * numDispVerts);
427
428    // Add the displaced vertices to the displaced vertex list
429    for (i = 0; i < numDispVerts; i++)
430        bsp_data->addDispVertex(dispverts[i]);
431
432    // Clean up
433    delete [] dispverts;
434}
435
436
437void VBSPReader::processGameData(std::istream & str, int offset, int length)
438{
439    GameHeader    gameHeader;
440    GameLump *    gameLumps;
441    int           i;
442
443    // Read the header
444    str.seekg(offset);
445    str.read((char *) &gameHeader, sizeof(GameHeader));
446
447    // Create and read in the game lump list
448    gameLumps = new GameLump[gameHeader.num_lumps];
449    str.read((char *) gameLumps, sizeof(GameLump) * gameHeader.num_lumps);
450
451    // Iterate over the game lumps
452    for (i = 0; i < gameHeader.num_lumps; i++)
453    {
454        // See if this is a lump we're interested in
455        if (gameLumps[i].lump_id == STATIC_PROP_ID)
456        {
457             processStaticProps(str, gameLumps[i].lump_offset,
458                                gameLumps[i].lump_length,
459                                gameLumps[i].lump_version);
460        }
461    }
462
463    // Clean up
464    delete [] gameLumps;
465}
466
467
468void VBSPReader::processStaticProps(std::istream & str, int offset, int length,
469                                    int lumpVersion)
470{
471    StaticPropModelNames    sprpModelNames;
472    char                    modelName[130];
473    std::string             modelStr;
474    int                     i;
475    StaticPropLeaves        sprpLeaves;
476    StaticProps             sprpHeader;
477    StaticPropV4            sprp4;
478    StaticProp              sprp5;
479
480    // First, read the static prop models dictionary
481    str.seekg(offset);
482    str.read((char *) &sprpModelNames, sizeof(StaticPropModelNames));
483    for (i = 0; i < sprpModelNames.num_model_names; i++)
484    {
485        str.read(modelName, 128);
486        modelName[128] = 0;
487        modelStr = std::string(modelName);
488        bsp_data->addStaticPropModel(modelStr);
489    }
490
491    // Next, skip over the static prop leaf array
492    str.read((char *) &sprpLeaves, sizeof(StaticPropLeaves));
493    str.seekg(sprpLeaves.num_leaf_entries * sizeof(unsigned short),
494              std::istream::cur);
495
496    // Finally, read in the static prop entries
497    str.read((char *) &sprpHeader, sizeof(StaticProps));
498    for (i = 0; i < sprpHeader.num_static_props; i++)
499    {
500        // The version number determines how much we read for each prop
501        if (lumpVersion == 4)
502        {
503            // Read the static prop and add it to the bsp data
504            str.read((char *) &sprp4, sizeof(StaticPropV4));
505            bsp_data->addStaticProp(sprp4);
506        }
507        else if (lumpVersion == 5)
508        {
509            // Read the static prop and add it to the bsp data
510            str.read((char *) &sprp5, sizeof(StaticProp));
511            bsp_data->addStaticProp(sprp5);
512        }
513    }
514}
515
516
517std::string VBSPReader::getToken(std::string str, const char * delim,
518                                 size_t & index)
519{
520    std::string   token;
521    size_t        end = std::string::npos;
522
523    // Look for the first non-occurrence of the delimiters
524    size_t start = str.find_first_not_of(delim, index);
525    if (start != std::string::npos)
526    {
527        // From there, look for the first occurrence of a delimiter
528        end = str.find_first_of(delim, start+1);
529        if (end != std::string::npos)
530        {
531            // Found a delimiter, so grab the string in between
532            token = str.substr(start, end-start);
533        }
534        else
535        {
536            // Ran off the end of the string, so just grab everything from
537            // the first good character
538            token = str.substr(start);
539        }
540    }
541    else
542    {
543        // No token to be found
544        token = "";
545    }
546
547    // Update the index (in case we want to keep looking for tokens in this
548    // string)
549    if (end != std::string::npos)
550        index = end+1;
551    else
552        index = std::string::npos;
553
554    // Return the token
555    return token;
556}
557
558
559ref_ptr<Texture> VBSPReader::readTextureFile(std::string textureName)
560{
561    std::string   texFile;
562    std::string   texPath;
563    osg::ref_ptr<Image>       texImage;
564    osg::ref_ptr<Texture>     texture;
565
566    // Find the texture's image file
567    texFile = std::string(textureName) + ".vtf";
568    texPath = findDataFile(texFile, CASE_INSENSITIVE);
569
570    // If we don't find it right away, check in a "materials" subdirectory
571    if (texPath.empty())
572    {
573        texFile = "materials/" + std::string(textureName) + ".vtf";
574        texPath = findDataFile(texFile, CASE_INSENSITIVE);
575
576        // Check up one directory if we don't find it here (the map file is
577        // usually located in the "maps" directory, adjacent to the materials
578        // directory)
579        if (texPath.empty())
580        {
581            texFile = "../materials/" + std::string(textureName) + ".vtf";
582            texPath = findDataFile(texFile, CASE_INSENSITIVE);
583        }
584    }
585
586    // If we found the file, read it, otherwise bail
587    if (!texPath.empty())
588    {
589        texImage = readRefImageFile(texPath);
590
591        // If we got the image, create the texture attribute
592        if (texImage != NULL)
593        {
594            // Create the texture
595            if (texImage->t() == 1)
596            {
597                texture = new Texture1D(texImage.get());
598            }
599            else if (texImage->r() == 1)
600            {
601                texture = new Texture2D(texImage.get());
602            }
603            else
604            {
605                texture = new Texture3D(texImage.get());
606            }
607
608            // Set texture attributes
609            texture->setWrap(Texture::WRAP_S, Texture::REPEAT);
610            texture->setWrap(Texture::WRAP_T, Texture::REPEAT);
611            texture->setWrap(Texture::WRAP_R, Texture::REPEAT);
612            texture->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
613            texture->setFilter(Texture::MIN_FILTER,
614                               Texture::LINEAR_MIPMAP_LINEAR);
615        }
616        else
617        {
618            // We were unable to find the texture file
619            notify(WARN) << "Couldn't find texture " << textureName;
620            notify(WARN) << std::endl;
621
622            // No texture
623            texture = NULL;
624        }
625    }
626    else
627    {
628        // We were unable to find the texture file
629        notify(WARN) << "Couldn't find texture " << textureName;
630        notify(WARN) << std::endl;
631
632        // No texture
633        texture = NULL;
634    }
635
636    return texture;
637}
638
639
640ref_ptr<StateSet> VBSPReader::createBlendShader(Texture * tex1, Texture * tex2)
641{
642    const char *  blendVtxShaderCode =
643    {
644        "attribute float vBlendParam;\n"
645        "\n"
646        "varying float fBlendParam;\n"
647        "\n"
648        "void main(void)\n"
649        "{\n"
650        "   vec3 normal, lightDir;\n"
651        "   vec4 ambient, diffuse;\n"
652        "   float nDotL;\n"
653        "\n"
654        "   // Simple directional lighting (for now).  We're assuming a\n"
655        "   // single light source\n"
656        "   // TODO:  This is only used for terrain geometry, so it should be\n"
657        "   //        lightmapped\n"
658        "   normal = normalize(gl_NormalMatrix * gl_Normal);\n"
659        "   lightDir = normalize(vec3(gl_LightSource[0].position));\n"
660        "   nDotL = max(dot(normal, lightDir), 0.0);\n"
661        "   ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;\n"
662        "   diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;\n"
663        "\n"
664        "   // Calculate the vertex color\n"
665        "   gl_FrontColor =  0.1 + ambient + nDotL * diffuse;\n"
666        "\n"
667        "   // Pass the texture blend parameter through to the fragment\n"
668        "   // shader\n"
669        "   fBlendParam = vBlendParam;\n"
670        "\n"
671        "   // The basic transforms\n"
672        "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
673        "   gl_TexCoord[0] = vec4(gl_MultiTexCoord0.st, 0.0, 0.0);\n"
674        "}\n"
675    };
676
677    const char *  blendFrgShaderCode =
678    {
679        "uniform sampler2D tex1;\n"
680        "uniform sampler2D tex2;\n"
681        "\n"
682        "varying float fBlendParam;\n"
683        "\n"
684        "void main(void)\n"
685        "{\n"
686        "   vec4 tex1Color;\n"
687        "   vec4 tex2Color;\n"
688        "\n"
689        "   tex1Color = texture2D(tex1, gl_TexCoord[0].st) *\n"
690        "      (1.0 - fBlendParam);\n"
691        "   tex2Color = texture2D(tex2, gl_TexCoord[0].st) * fBlendParam;\n"
692        "\n"
693        "   gl_FragColor = gl_Color * (tex1Color + tex2Color);\n"
694        "}\n"
695    };
696
697    // Create the stateset
698    StateSet * stateSet = new StateSet();
699 
700    // Add the two textures
701    stateSet->setTextureAttributeAndModes(0, tex1, StateAttribute::ON);
702    stateSet->setTextureAttributeAndModes(1, tex2, StateAttribute::ON);
703
704    // Create the vertex and fragment shaders
705    Shader * blendVtxShader = new Shader(Shader::VERTEX);
706    blendVtxShader->setShaderSource(blendVtxShaderCode);
707    Shader * blendFrgShader = new Shader(Shader::FRAGMENT);
708    blendFrgShader->setShaderSource(blendFrgShaderCode);
709
710    // Create the two texture uniforms
711    Uniform * tex1Sampler = new Uniform(Uniform::SAMPLER_2D, "tex1");
712    tex1Sampler->set(0);
713    Uniform * tex2Sampler = new Uniform(Uniform::SAMPLER_2D, "tex2");
714    tex2Sampler->set(1);
715
716    // Create the program
717    Program * blendProgram = new Program();
718    blendProgram->addShader(blendVtxShader);
719    blendProgram->addShader(blendFrgShader);
720
721    // The texture blending parameter will be on vertex attribute 1
722    blendProgram->addBindAttribLocation("vBlendParam", (GLuint) 1);
723
724    // Add everything to the StateSet
725    stateSet->addUniform(tex1Sampler);
726    stateSet->addUniform(tex2Sampler);
727    stateSet->setAttributeAndModes(blendProgram, StateAttribute::ON);
728
729    // Return the StateSet
730    return stateSet;
731}
732
733
734ref_ptr<StateSet> VBSPReader::readMaterialFile(std::string materialName)
735{
736    std::string             mtlFileName;
737    std::string             mtlPath;
738    osgDB::ifstream *       mtlFile;
739    std::string             line;
740    std::string::size_type  start = std::string::npos;
741    std::string             token;
742    bool                    found = false;
743    ref_ptr<StateSet>       stateSet;
744    std::string             shaderName;
745    std::string             texName;
746    std::string             tex2Name;
747    ref_ptr<Texture>        texture;
748    ref_ptr<Texture>        texture2;
749    ref_ptr<Material>       material;
750    ref_ptr<BlendFunc>      blend;
751    bool                    translucent;
752    double                  alpha;
753
754    // Find the material file
755    mtlFileName = std::string(materialName) + ".vmt";
756    mtlPath = findDataFile(mtlFileName, CASE_INSENSITIVE);
757
758    // If we don't find it right away, check in a "materials" subdirectory
759    if (mtlPath.empty())
760    {
761        mtlFileName = "materials/" + std::string(materialName) + ".vmt";
762        mtlPath = findDataFile(mtlFileName, CASE_INSENSITIVE);
763
764        // Check up one directory if we don't find it here (the map file is
765        // usually located in the "maps" directory, adjacent to the materials
766        // directory)
767        if (mtlPath.empty())
768        {
769            mtlFileName = "../materials/" + std::string(materialName) + ".vmt";
770            mtlPath = findDataFile(mtlFileName, CASE_INSENSITIVE);
771        }
772    }
773
774    // See if we found the file
775    if (!mtlPath.empty())
776    {
777        // Try to open the file, bail out if we fail
778        mtlFile = new osgDB::ifstream(mtlPath.c_str(), std::ifstream::in);
779        if (!mtlFile)
780            return NULL;
781    }
782    else
783    {
784        // Didn't find the material file, so return NULL
785        notify(WARN) << "Can't find material " << materialName << std::endl;
786        return NULL;
787    }
788
789    // First, look for the shader name
790    found = false;
791    while ((!found) && (!mtlFile->eof()))
792    {
793        // Read a line from the file
794        std::getline(*mtlFile, line);
795
796        // Try to find the shader name
797        start = 0;
798        token = getToken(line, " \t\n\r\"", start);
799
800        // If we got something, it must be the shader
801        if ((!token.empty()) && (token.compare(0, 2, "//") != 0))
802        {
803            shaderName = token;
804            found = true;
805        }
806    }
807
808    // If we didn't find a shader, this isn't a valid material file
809    if (!found)
810    {
811        mtlFile->close();
812        notify(WARN) << "Material " << materialName << " isn't valid.";
813        notify(WARN) << std::endl;
814        return NULL;
815    }
816
817    // No textures loaded yet
818    texture = NULL;
819    texture2 = NULL;
820
821    // Assume no transparency unless the properties say otherwise
822    translucent = false;
823
824    // Assume fully opaque
825    alpha = 1.0;
826
827    // Read the material properties next
828    while (!mtlFile->eof())
829    {
830        // Get the next line
831        std::getline(*mtlFile, line);
832
833        // Look for tokens starting at the beginning
834        start = 0;
835        token = getToken(line, " \t\n\r\"", start);
836
837        while ((!token.empty()) && (token.compare(0, 2, "//") != 0))
838        {
839            if (equalCaseInsensitive(token, "$basetexture"))
840            {
841                // Get the base texture name
842                token = getToken(line, " \t\n\r\"", start);
843
844                // Read the texture
845                if (!token.empty())
846                    texture = readTextureFile(token);
847            }
848            else if (equalCaseInsensitive(token, "$basetexture2"))
849            {
850                // Get the second base texture name
851                token = getToken(line, " \t\n\r\"", start);
852
853                // Read the texture
854                if (!token.empty())
855                    texture2 = readTextureFile(token);
856            }
857            else if ((equalCaseInsensitive(token, "$translucent")) ||
858                     (equalCaseInsensitive(token, "$alphatest")))
859            {
860                // Get the translucency setting
861                token = getToken(line, " \t\n\r\"", start);
862
863                // Interpret the setting
864                if ((token == "1") || (token == "true"))
865                     translucent = true;
866            }
867            else if (equalCaseInsensitive(token, "$alpha"))
868            {
869                // Get the translucency setting
870                token = getToken(line, " \t\n\r\"", start);
871
872                // Interpret the setting
873                if (!token.empty())
874                {
875                   alpha = osg::asciiToDouble(token.c_str());
876                }
877            }
878 
879            // Try the next token
880            token = getToken(line, " \t\n\r\"", start);
881        }
882    }
883
884    // Start with no StateSet (in case the stuff below fails)
885    stateSet = NULL;
886
887    // Check the shader's name
888    if (equalCaseInsensitive(shaderName, "WorldVertexTransition"))
889    {
890        // This shader blends between two textures based on a per-vertex
891        // attribute.  This is used for displaced terrain surfaces in HL2 maps.
892        stateSet = createBlendShader(texture.get(), texture2.get());
893
894        // Add a material to the state set
895        material = new Material();
896        material->setAmbient(Material::FRONT_AND_BACK,
897                             Vec4(1.0, 1.0, 1.0, 1.0) );
898        material->setDiffuse(Material::FRONT_AND_BACK,
899                             Vec4(1.0, 1.0, 1.0, 1.0) );
900        material->setSpecular(Material::FRONT_AND_BACK,
901                              Vec4(0.0, 0.0, 0.0, 1.0) );
902        material->setShininess(Material::FRONT_AND_BACK, 1.0);
903        material->setEmission(Material::FRONT_AND_BACK,
904                              Vec4(0.0, 0.0, 0.0, 1.0) );
905        material->setAlpha(Material::FRONT_AND_BACK, alpha);
906        stateSet->setAttributeAndModes(material.get(), StateAttribute::ON);
907    }
908    else if (equalCaseInsensitive(shaderName, "UnlitGeneric"))
909    {
910        // Create the StateSet
911        stateSet = new StateSet();
912
913        // Disable lighting on this StateSet
914        stateSet->setMode(GL_LIGHTING, StateAttribute::OFF);
915
916        // Add the texture attribute (or disable texturing if no base texture)
917        if (texture != NULL)
918        {
919            stateSet->setTextureAttributeAndModes(0, texture.get(),
920                                                  StateAttribute::ON);
921
922            // See if the material is translucent
923            if (translucent)
924            {
925                // Create and apply a blend function attribute to the
926                // state set
927                blend = new BlendFunc(BlendFunc::SRC_ALPHA,
928                                      BlendFunc::ONE_MINUS_SRC_ALPHA);
929                stateSet->setAttributeAndModes(blend.get(), StateAttribute::ON);
930
931                // Set the state set's rendering hint to transparent
932                stateSet->setRenderingHint(StateSet::TRANSPARENT_BIN);
933            }
934        }
935        else
936        {
937            notify(WARN) << "No base texture for material " << materialName;
938            notify(WARN) << std::endl;
939            stateSet->setTextureMode(0, GL_TEXTURE_2D, StateAttribute::OFF);
940        }
941    }
942    else
943    {
944        // All other shaders fall back to fixed function
945        // TODO:  LightMappedGeneric shader
946
947        // Create the StateSet
948        stateSet = new StateSet();
949
950        // Add a material to the state set
951        material = new Material();
952        material->setAmbient(Material::FRONT_AND_BACK,
953                             Vec4(1.0, 1.0, 1.0, 1.0) );
954        material->setDiffuse(Material::FRONT_AND_BACK,
955                             Vec4(1.0, 1.0, 1.0, 1.0) );
956        material->setSpecular(Material::FRONT_AND_BACK,
957                              Vec4(0.0, 0.0, 0.0, 1.0) );
958        material->setShininess(Material::FRONT_AND_BACK, 1.0);
959        material->setEmission(Material::FRONT_AND_BACK,
960                              Vec4(0.0, 0.0, 0.0, 1.0) );
961        material->setAlpha(Material::FRONT_AND_BACK, alpha);
962        stateSet->setAttributeAndModes(material.get(), StateAttribute::ON);
963
964        // Add the texture attribute (or disable texturing if no base texture)
965        if (texture != NULL)
966        {
967            stateSet->setTextureAttributeAndModes(0, texture.get(),
968                                                  StateAttribute::ON);
969
970            // See if the material is translucent
971            if (translucent)
972            {
973                // Create and apply a blend function attribute to the
974                // state set
975                blend = new BlendFunc(BlendFunc::SRC_ALPHA,
976                                      BlendFunc::ONE_MINUS_SRC_ALPHA);
977                stateSet->setAttributeAndModes(blend.get(), StateAttribute::ON);
978
979                // Set the state set's rendering hint to transparent
980                stateSet->setRenderingHint(StateSet::TRANSPARENT_BIN);
981            }
982        }
983        else
984        {
985            notify(WARN) << "No base texture for material " << materialName;
986            notify(WARN) << std::endl;
987            stateSet->setTextureMode(0, GL_TEXTURE_2D, StateAttribute::OFF);
988        }
989    }
990
991    // Close the file
992    mtlFile->close();
993
994    // Return the resulting StateSet
995    return stateSet;
996}
997
998
999void VBSPReader::createScene()
1000{
1001    ref_ptr<Group>              group;
1002    ref_ptr<Group>              subGroup;
1003    TexData                     currentTexData;
1004    const char *                texName;
1005    char                        currentTexName[256];
1006    char                        prefix[64];
1007    char *                      mtlPtr;
1008    char *                      tmpPtr;
1009    char                        tempTex[256];
1010    std::string                 entityText;
1011    VBSPEntity *                currentEntity;
1012    int                         i;
1013    ref_ptr<StateSet>           stateSet;
1014    StaticProp                  staticProp;
1015    Matrixf                     transMat, rotMat;
1016    Quat                        yaw, pitch, roll;
1017    ref_ptr<MatrixTransform>    propXform;
1018    std::string                 propModel;
1019    std::string                 propFile;
1020    ref_ptr<Node>               propNode;
1021
1022    // Load the materials and create a StateSet for each one
1023    for (i = 0; i < bsp_data->getNumTexDatas(); i++)
1024    {
1025        // Get the texdata entry and texture name
1026        currentTexData = bsp_data->getTexData(i);
1027        texName = bsp_data->
1028            getTexDataString(currentTexData.name_string_table_id).c_str();
1029        strcpy(currentTexName, texName);
1030
1031        // See if this is referring to an environment mapped material (we don't
1032        // handle this yet)
1033        sprintf(prefix, "maps/%s/", map_name.c_str());
1034        if (strncmp(currentTexName, prefix, strlen(prefix)) == 0)
1035        {
1036            // This texture is referring to this map's PAK file, so it could
1037            // be an environment mapped texture (an existing material that is
1038            // modified by a cube map of the scene).  If so, we just need to
1039            // get the base material name
1040            mtlPtr = currentTexName;
1041            mtlPtr += strlen(prefix);
1042
1043            // Now, we're pointing at the path to the material itself, so copy
1044            // what we've got so far
1045            strcpy(tempTex, mtlPtr);
1046
1047            // Now, we just need to trim the two or three cube map coordinates
1048            // from the end.
1049            // This isn't a perfect solution, but it should catch most cases.
1050            // The right way to do this would be to read the .vmt file from the
1051            // map's PAKFILE lump, and make use of the basetexture parameter in
1052            // it
1053            tmpPtr = strrchr(tempTex, '/');
1054            mtlPtr = strrchr(tempTex, '_');
1055            if ((mtlPtr != NULL) && (mtlPtr > tmpPtr))
1056                *mtlPtr = 0;
1057            mtlPtr = strrchr(tempTex, '_');
1058            if ((mtlPtr != NULL) && (mtlPtr > tmpPtr))
1059                *mtlPtr = 0;
1060            mtlPtr = strrchr(tempTex, '_');
1061            if ((mtlPtr != NULL) && (mtlPtr > tmpPtr))
1062                *mtlPtr = 0;
1063
1064            // That should be it, so make it the texture name
1065            strcpy(currentTexName, tempTex);
1066        }
1067
1068        // Read the material for this geometry
1069        stateSet = readMaterialFile(currentTexName);
1070
1071        // Whether we successfully created a StateSet or not, add it to the
1072        // bsp data list now
1073        bsp_data->addStateSet(stateSet.get());
1074    }
1075
1076    // Create the root group for the scene
1077    group = new Group();
1078
1079    // Iterate through the list of entities, and try to convert all the
1080    // visible entities to geometry
1081    for (i = 0; i < bsp_data->getNumEntities(); i++)
1082    {
1083        // Get the entity
1084        entityText = bsp_data->getEntity(i);
1085        currentEntity = new VBSPEntity(entityText, bsp_data);
1086
1087        // See if the entity is visible
1088        if (currentEntity->isVisible())
1089        {
1090            // Create geometry for the entity
1091            subGroup = currentEntity->createGeometry();
1092
1093            // If the entity's geometry is valid, add it to the main group
1094            if (subGroup.valid())
1095                group->addChild(subGroup.get());
1096        }
1097
1098        // Done with this entity
1099        delete currentEntity;
1100    }
1101
1102    // Iterate through the list of static props, and add them to the scene
1103    // as well
1104    for (i = 0; i < bsp_data->getNumStaticProps(); i++)
1105    {
1106        // Get the static prop
1107        staticProp = bsp_data->getStaticProp(i);
1108
1109        // Create a MatrixTransform for this prop (scale the position from
1110        // inches to meters)
1111        transMat.makeTranslate(staticProp.prop_origin * 0.0254);
1112        pitch.makeRotate(osg::DegreesToRadians(staticProp.prop_angles.x()),
1113                         Vec3f(0.0, 1.0, 0.0));
1114        yaw.makeRotate(osg::DegreesToRadians(staticProp.prop_angles.y()),
1115                       Vec3f(0.0, 0.0, 1.0));
1116        roll.makeRotate(osg::DegreesToRadians(staticProp.prop_angles.z()),
1117                        Vec3f(1.0, 0.0, 0.0));
1118        rotMat.makeRotate(roll * pitch * yaw);
1119        propXform = new MatrixTransform();
1120        propXform->setMatrix(rotMat * transMat);
1121
1122        // Load the prop's model
1123        propModel = bsp_data->getStaticPropModel(staticProp.prop_type);
1124        propNode = osgDB::readNodeFile(propModel);
1125
1126        // If we loaded the prop correctly, add it to the scene
1127        if (propNode.valid())
1128        {
1129            // Add the model to the transform node, and attach the transform
1130            // to the scene
1131            propXform->addChild(propNode.get());
1132            group->addChild(propXform.get());
1133
1134            // Name the prop
1135            propXform->setName(std::string("prop_static:" + propModel));
1136        }
1137        else
1138        {
1139            notify(WARN) << "Couldn't find static prop \"" << propModel;
1140            notify(WARN) << "\"." << std::endl;
1141
1142            // Couldn't find the prop, so get rid of the transform node
1143            propXform = NULL;
1144        }
1145    }
1146
1147    // Set the root node to the result
1148    root_node = group.get();
1149}
1150
1151
1152bool VBSPReader::readFile(const std::string & file)
1153{
1154    osgDB::ifstream *   mapFile = 0;
1155    Header              header;
1156    int                 i = 0;
1157
1158    // Remember the map name
1159    map_name = getStrippedName(file);
1160
1161    mapFile = new osgDB::ifstream(file.c_str(), std::ios::binary);
1162    if (!mapFile)
1163        return false;
1164
1165    // Read the header
1166    mapFile->read((char *) &header, sizeof(Header));
1167
1168    // Load the bsp file lumps that we care about
1169    for (i = 0; i < MAX_LUMPS; i++)
1170    {
1171        if ((header.lump_table[i].file_offset != 0) &&
1172            (header.lump_table[i].lump_length != 0))
1173        {
1174            // Process the lump
1175            switch (i)
1176            {
1177                case ENTITIES_LUMP:
1178                    processEntities(*mapFile, header.lump_table[i].file_offset,
1179                                    header.lump_table[i].lump_length);
1180                    break;
1181                case PLANES_LUMP:
1182                    processPlanes(*mapFile, header.lump_table[i].file_offset,
1183                                  header.lump_table[i].lump_length);
1184                    break;
1185                case VERTICES_LUMP:
1186                    processVertices(*mapFile, header.lump_table[i].file_offset,
1187                                    header.lump_table[i].lump_length);
1188                    break;
1189                case EDGES_LUMP:
1190                    processEdges(*mapFile, header.lump_table[i].file_offset,
1191                                 header.lump_table[i].lump_length);
1192                    break;
1193                case SURFEDGES_LUMP:
1194                    processSurfEdges(*mapFile, header.lump_table[i].file_offset,
1195                                     header.lump_table[i].lump_length);
1196                    break;
1197                case MODELS_LUMP:
1198                    processModels(*mapFile, header.lump_table[i].file_offset,
1199                                  header.lump_table[i].lump_length);
1200                    break;
1201                case FACES_LUMP:
1202                    processFaces(*mapFile, header.lump_table[i].file_offset,
1203                                 header.lump_table[i].lump_length);
1204                    break;
1205                case TEXINFO_LUMP:
1206                    processTexInfo(*mapFile, header.lump_table[i].file_offset,
1207                                   header.lump_table[i].lump_length);
1208                    break;
1209                case TEXDATA_LUMP:
1210                    processTexData(*mapFile, header.lump_table[i].file_offset,
1211                                   header.lump_table[i].lump_length);
1212                    break;
1213                case TEXDATA_STRING_TABLE_LUMP:
1214                    processTexDataStringTable(*mapFile,
1215                                              header.lump_table[i].file_offset,
1216                                              header.lump_table[i].lump_length);
1217                    break;
1218                case TEXDATA_STRING_DATA_LUMP:
1219                    processTexDataStringData(*mapFile,
1220                                             header.lump_table[i].file_offset,
1221                                             header.lump_table[i].lump_length);
1222                    break;
1223                case DISPINFO_LUMP:
1224                    processDispInfo(*mapFile, header.lump_table[i].file_offset,
1225                                    header.lump_table[i].lump_length);
1226                    break;
1227                case DISP_VERTS_LUMP:
1228                    processDispVerts(*mapFile, header.lump_table[i].file_offset,
1229                                     header.lump_table[i].lump_length);
1230                    break;
1231                case GAME_LUMP:
1232                    processGameData(*mapFile, header.lump_table[i].file_offset,
1233                                    header.lump_table[i].lump_length);
1234                    break;
1235            }
1236        }
1237    }
1238
1239    // Create the OSG scene from the BSP data
1240    createScene();
1241    return true;
1242}
1243
1244
1245ref_ptr<Node> VBSPReader::getRootNode()
1246{
1247    return root_node;
1248}
1249
Note: See TracBrowser for help on using the browser.