root/OpenSceneGraph/trunk/src/osgPlugins/bsp/VBSPReader.cpp @ 10539

Revision 10539, 38.7 kB (checked in by robert, 5 years ago)

From Colin McDonald?, "The bsp & mdl plugins have calls to atof() without including the
associated <stdlib.h> header. This breaks the build on my Solaris setup.

Rather than adding the missing <stdlib.h> include, I have changed the
atof() calls to osg::asciiToDouble(). This is the same as was done
throughout the other plugins recently, for locale independance.

I've attached updates to the svn trunk, the fix is also appropriate for
the 2.8.* branch."

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