Coverage Report

Created: 2025-10-10 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/PlugIns/BSPSceneManager/src/OgreQuake3Shader.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
29
#include "OgreQuake3Shader.h"
30
#include "OgreSceneManager.h"
31
#include "OgreMaterial.h"
32
#include "OgreTechnique.h"
33
#include "OgrePass.h"
34
#include "OgreTextureUnitState.h"
35
#include "OgreMath.h"
36
#include "OgreLogManager.h"
37
#include "OgreTextureManager.h"
38
#include "OgreRoot.h"
39
#include "OgreMaterialManager.h"
40
41
namespace Ogre {
42
43
44
    //-----------------------------------------------------------------------
45
    Quake3Shader::Quake3Shader(const String& name)
46
0
    {
47
0
        mName = name;
48
0
        numPasses = 0;
49
0
        deformFunc = DEFORM_FUNC_NONE;
50
0
        farbox = false;
51
0
        skyDome = false;
52
0
        flags = 0;
53
0
        fog = false;
54
0
        cullMode = MANUAL_CULL_BACK;
55
56
0
    }
57
    //-----------------------------------------------------------------------
58
    Quake3Shader::~Quake3Shader()
59
0
    {
60
0
    }
61
    //-----------------------------------------------------------------------
62
    MaterialPtr Quake3Shader::createAsMaterial(int lightmapNumber)
63
0
    {
64
0
        String matName;
65
0
        StringStream str;
66
0
        String resourceGroup = ResourceGroupManager::getSingleton().getWorldResourceGroupName();
67
68
0
        str << mName << "#" << lightmapNumber;
69
0
        matName = str.str();
70
71
0
        MaterialPtr mat = MaterialManager::getSingleton().create(matName, 
72
0
            resourceGroup);
73
0
        Ogre::Pass* ogrePass = mat->getTechnique(0)->getPass(0);
74
75
0
        LogManager::getSingleton().logMessage("Using Q3 shader " + mName, LML_TRIVIAL);
76
0
        for (int p = 0; p < numPasses; ++p)
77
0
        {
78
0
            TextureUnitState* t;
79
            // Create basic texture
80
0
            if (pass[p].textureName == "$lightmap")
81
0
            {
82
0
                StringStream str2;
83
0
                str2 << "@lightmap" << lightmapNumber;
84
0
                t = ogrePass->createTextureUnitState(str2.str());
85
0
            }
86
            // Animated texture support
87
0
            else if (pass[p].animNumFrames > 0)
88
0
            {
89
0
                Real sequenceTime = pass[p].animNumFrames / pass[p].animFps;
90
                /* Pre-load textures
91
                   We need to know if each one was loaded OK since extensions may change for each
92
                   Quake3 can still include alternate extension filenames e.g. jpg instead of tga
93
                   Pain in the arse - have to check for each frame as letters<n>.tga for example
94
                   is different per frame!
95
                */
96
0
                for (unsigned int alt = 0; alt < pass[p].animNumFrames; ++alt)
97
0
                {
98
0
                    if (!ResourceGroupManager::getSingleton().resourceExists(
99
0
                        resourceGroup, pass[p].frames[alt]))
100
0
                    {
101
                        // Try alternate extension
102
0
                        pass[p].frames[alt] = getAlternateName(pass[p].frames[alt]);
103
0
                        if (!ResourceGroupManager::getSingleton().resourceExists(
104
0
                            resourceGroup, pass[p].frames[alt]))
105
0
                        { 
106
                            // stuffed - no texture
107
0
                            continue;
108
0
                        }
109
0
                    }
110
111
0
                }
112
113
0
                t = ogrePass->createTextureUnitState("");
114
0
                t->setAnimatedTextureName(pass[p].frames, pass[p].animNumFrames, sequenceTime);
115
116
0
            }
117
0
            else
118
0
            {
119
                // Quake3 can still include alternate extension filenames e.g. jpg instead of tga
120
                // Pain in the arse - have to check for failure
121
0
                if (!ResourceGroupManager::getSingleton().resourceExists(
122
0
                    resourceGroup, pass[p].textureName))
123
0
                {
124
                    // Try alternate extension
125
0
                    pass[p].textureName = getAlternateName(pass[p].textureName);
126
0
                    if (!ResourceGroupManager::getSingleton().resourceExists(
127
0
                        resourceGroup, pass[p].textureName))
128
0
                    { 
129
                        // stuffed - no texture
130
0
                        continue;
131
0
                    }
132
0
                }
133
0
                t = ogrePass->createTextureUnitState(pass[p].textureName);
134
0
            }
135
            // Blending
136
0
            if (p == 0)
137
0
            {
138
                // scene blend
139
0
                mat->setSceneBlending(pass[p].blendSrc, pass[p].blendDest);
140
0
                if (mat->isTransparent())
141
0
                    mat->setDepthWriteEnabled(false);
142
143
0
                t->setColourOperation(LBO_REPLACE);
144
                // Alpha mode
145
0
                ogrePass->setAlphaRejectSettings(
146
0
                    pass[p].alphaFunc, pass[p].alphaVal);
147
0
            }
148
0
            else
149
0
            {
150
0
                if (pass[p].customBlend)
151
0
                {
152
                    // Fallback for now
153
0
                    t->setColourOperation(LBO_MODULATE);
154
0
                }
155
0
                else
156
0
                {
157
                    // simple layer blend
158
0
                    t->setColourOperation(pass[p].blend);
159
0
                }
160
                // Alpha mode, prefer 'most alphary'
161
0
                CompareFunction currFunc = ogrePass->getAlphaRejectFunction();
162
0
                unsigned char currVal = ogrePass->getAlphaRejectValue();
163
0
                if (pass[p].alphaFunc > currFunc ||
164
0
                    (pass[p].alphaFunc == currFunc && pass[p].alphaVal < currVal))
165
0
                {
166
0
                    ogrePass->setAlphaRejectSettings(
167
0
                        pass[p].alphaFunc, pass[p].alphaVal);
168
0
                }
169
0
            }
170
            // Tex coords
171
0
            if (pass[p].texGen == TEXGEN_BASE)
172
0
            {
173
0
                t->setTextureCoordSet(0);
174
0
            }
175
0
            else if (pass[p].texGen == TEXGEN_LIGHTMAP)
176
0
            {
177
0
                t->setTextureCoordSet(1);
178
0
            }
179
0
            else if (pass[p].texGen == TEXGEN_ENVIRONMENT)
180
0
            {
181
0
                t->setEnvironmentMap(true, TextureUnitState::ENV_CURVED);
182
0
            }
183
            // Tex mod
184
            // Scale
185
0
            t->setTextureUScale(pass[p].tcModScale[0]);
186
0
            t->setTextureVScale(pass[p].tcModScale[1]);
187
            // Procedural mods
188
            // Custom - don't use mod if generating environment
189
            // Because I do env a different way it look horrible
190
0
            if (pass[p].texGen != TEXGEN_ENVIRONMENT)
191
0
            {
192
0
                if (pass[p].tcModRotate)
193
0
                {
194
0
                    t->setRotateAnimation(pass[p].tcModRotate);
195
0
                }
196
0
                if (pass[p].tcModScroll[0] || pass[p].tcModScroll[1])
197
0
                {
198
0
                    if (pass[p].tcModTurbOn)
199
0
                    {
200
                        // Turbulent scroll
201
0
                        if (pass[p].tcModScroll[0])
202
0
                        {
203
0
                            t->setTransformAnimation(TextureUnitState::TT_TRANSLATE_U, WFT_SINE,
204
0
                                pass[p].tcModTurb[0], pass[p].tcModTurb[3], pass[p].tcModTurb[2], pass[p].tcModTurb[1]);
205
0
                        }
206
0
                        if (pass[p].tcModScroll[1])
207
0
                        {
208
0
                            t->setTransformAnimation(TextureUnitState::TT_TRANSLATE_V, WFT_SINE,
209
0
                                pass[p].tcModTurb[0], pass[p].tcModTurb[3], pass[p].tcModTurb[2], pass[p].tcModTurb[1]);
210
0
                        }
211
0
                    }
212
0
                    else
213
0
                    {
214
                        // Constant scroll
215
0
                        t->setScrollAnimation(pass[p].tcModScroll[0], pass[p].tcModScroll[1]);
216
0
                    }
217
0
                }
218
0
                if (pass[p].tcModStretchWave != SHADER_FUNC_NONE)
219
0
                {
220
0
                    WaveformType wft = WFT_SINE;
221
0
                    switch(pass[p].tcModStretchWave)
222
0
                    {
223
0
                    case SHADER_FUNC_SIN:
224
0
                        wft = WFT_SINE;
225
0
                        break;
226
0
                    case SHADER_FUNC_TRIANGLE:
227
0
                        wft = WFT_TRIANGLE;
228
0
                        break;
229
0
                    case SHADER_FUNC_SQUARE:
230
0
                        wft = WFT_SQUARE;
231
0
                        break;
232
0
                    case SHADER_FUNC_SAWTOOTH:
233
0
                        wft = WFT_SAWTOOTH;
234
0
                        break;
235
0
                    case SHADER_FUNC_INVERSESAWTOOTH:
236
0
                        wft = WFT_INVERSE_SAWTOOTH;
237
0
                        break;
238
0
                    default:
239
0
                        break;
240
0
                    }
241
                    // Create wave-based stretcher
242
0
                    t->setTransformAnimation(TextureUnitState::TT_SCALE_U, wft, pass[p].tcModStretchParams[3],
243
0
                        pass[p].tcModStretchParams[0], pass[p].tcModStretchParams[2], pass[p].tcModStretchParams[1]);
244
0
                    t->setTransformAnimation(TextureUnitState::TT_SCALE_V, wft, pass[p].tcModStretchParams[3],
245
0
                        pass[p].tcModStretchParams[0], pass[p].tcModStretchParams[2], pass[p].tcModStretchParams[1]);
246
0
                }
247
0
            }
248
            // Address mode
249
0
            t->setTextureAddressingMode(pass[p].addressMode);
250
251
            //assert(!t->isBlank());
252
253
254
0
        }
255
        // Do farbox (create new material)
256
257
        // Set culling mode and lighting to defaults
258
0
        mat->setCullingMode(CULL_NONE);
259
0
        mat->setManualCullingMode(cullMode);
260
0
        mat->setLightingEnabled(false);
261
0
        mat->load();
262
0
        return mat;
263
0
    }
264
    String Quake3Shader::getAlternateName(const String& texName)
265
0
    {
266
        // Get alternative JPG to TGA and vice versa
267
0
        String ext, base;
268
0
        StringUtil::splitBaseFilename(texName, base, ext);
269
0
        if (StringUtil::endsWith(ext, "jpg"))
270
0
        {
271
0
            return base + ".tga";
272
0
        }
273
0
        else
274
0
        {
275
0
            return base + ".jpg";
276
0
        }
277
278
0
    }
279
}