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

Revision 10507, 38.6 kB (checked in by robert, 5 years ago)

From Jason Daly, "This set of changes reworks the BSP plugin to use TexEnvCombine? instead of a GLSL program for doing the texture blending on displaced terrain geometry. After working with it a while, I found this method to be more scene graph friendly (at least until Wojtek gets his VirtualProgram? scheme working ;-) )

Note that this technique will require ARB_texture_env_crossbar (or NV_texture_env_combine4), as it mixes two textures in the first texture unit, and just does the lighting in the second. I doubt this will be a problem for any card that can already handle GLSL programs, though."

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