This file is indexed.

/usr/src/castle-game-engine-5.0.0/x3d/opengl/castlerendererinternaltextureenv.pas is in castle-game-engine-src 5.0.0-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
{
  Copyright 2002-2014 Michalis Kamburelis.

  This file is part of "Castle Game Engine".

  "Castle Game Engine" is free software; see the file COPYING.txt,
  included in this distribution, for details about the copyright.

  "Castle Game Engine" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  ----------------------------------------------------------------------------
}

{ Texture environment detection.
  @exclude Internal unit for CastleRenderer and CastleRendererInternalShader. }
unit CastleRendererInternalTextureEnv;

interface

type
  { Source of color for texture mixing.
    Used to represent MultiTexture.source X3D field.
    And used to represent the source of alpha value,
    for MultiTexture.mode = BLEND* case. }
  TColorSource = (
    { Material (OpenGL calls this "primary color"). }
    csMaterial,
    { Current texture unit color. }
    csCurrentTexture,
    { Constant color. (MultiTexture.color/alpha fields;
      for TInterpolateAlphaSource, actually this indicates only MultiTexture.alpha.) }
    csConstant,
    { Previous texture unit color, or material (in case this is the first texture unit). }
    csPreviousTexture);

  { OpenGL texture environment argument: none, GL_SOURCE0 or GL_SOURCE1. }
  TTextureEnvArgument = (taNone, ta0, ta1);

  { Function for texture mixing, corresponds to X3D MultiTexture.function field. }
  TTextureFunction = (tfNone, tfComplement, tfAlphaReplicate);

  { How to combine textures, on a single channel. }
  TCombine = (coModulate, coReplace, coAddSigned, coAdd, coSubtract, coInterpolate,
    coDot3Rgb, coDot3Rgba);

  TChannel = (cRGB, cAlpha);
  TCombinePerChannel = array [TChannel] of TCombine;
  TArgPerChannel = array [TChannel] of TTextureEnvArgument;
  TScalePerChannel = array [TChannel] of Single;
  TSourcePerChannel = array [TChannel] of TColorSource;

  { How to mix the current texture color into the fragment color. }
  TTextureEnv = object
  public
    { How to calculate given fragment channel using this texture unit.
      Returned values correspond to parameters of
      GL_COMBINE_RGB_EXT, GL_COMBINE_ALPHA_EXT.
      For some details about particular values,
      see OpenGL EXT_texture_env_combine extension
      (http://www.opengl.org/registry/specs/EXT/texture_env_combine.txt). }
    Combine: TCombinePerChannel;

    { Where should we load the current texture unit
      (this is "Arg1" in X3D spec wording; Arg1 is always current texture,
      indicated by X3D spec wording "The source field determines
      the colour source for the second argument.") }
    CurrentTextureArgument: TArgPerChannel;

    { Where should we load the @link(Source) color. This is "Arg2" in X3D spec. }
    SourceArgument: TArgPerChannel;

    { Scaling of given channel value.
      Fixed-function pipeline OpenGL allows only 1.0, 2.0 and 4.0 scales,
      and only such values will be set by TTextureEnv.Init. }
    Scale: TScalePerChannel;

    Disabled: boolean;
    NeedsConstantColor: boolean;

    { If, and only if, one of SourceArgument is not taNone,
      then SourceArgument should be loaded with this color. }
    Source: TSourcePerChannel;

    TextureFunction: TTextureFunction;

    { If, and only if, one of Combine is coInterpolate,
      then this specifies what is the OpenGL GL_SOURCE2.
      It should be filled (both RGB and alpha) with alpha from this source. }
    InterpolateAlphaSource: TColorSource;

    { Initialize based on MultiTexture.mode, MultiTexture.source,
      MultiTexture.function values.
      This does not setup any OpenGL state, it only calculates fields
      of this object. }
    constructor Init(const Mode, SourceStr, FunctionStr: string);

    { Calculate values based on simple OpenGL mode value. }
    constructor Init(const Mode: TCombine);

    function Hash: LongWord;
  end;

implementation

uses SysUtils, CastleStringUtils, CastleWarnings;

{ Simple type constructors, for ease of coding.
  Versions with only 1 argument set both channel (rgb and alpha) to the same. }
function CombinePerChannel(const RGB, Alpha: TCombine): TCombinePerChannel;
begin
  Result[cRGB] := RGB;
  Result[cAlpha] := Alpha;
end;

function CombinePerChannel(const Value: TCombine): TCombinePerChannel;
begin
  Result := CombinePerChannel(Value, Value);
end;

function ArgPerChannel(const Value: TTextureEnvArgument): TArgPerChannel;
begin
  Result[cRGB] := Value;
  Result[cAlpha] := Value;
end;

type
  TStringPerChannel = array [TChannel] of string;

{ If S contains two separate modes (one for RGB, one for Alpha)
  returns @true and sets PerChannel to these separate strings.
  Strings returned in PerChannel will not contain the separator
  (slash, comma), and will not contain whitespace. }
function SplitStringPerChannel(const S: string;
  out PerChannel: TStringPerChannel): boolean;
var
  P: Integer;
begin
  P := CharsPos(['/', ','], S);
  Result := P > 0;
  if Result then
  begin
    PerChannel[cRGB] := Trim(Copy(S, 1, P - 1));
    PerChannel[cAlpha] := Trim(SEnding(S, P + 1));
  end;
end;

{ Calculate values knowing MultiTexture.mode value. }
procedure ModeFromString(const S: string;
  out Combine: TCombinePerChannel;
  out CurrentTextureArgument: TArgPerChannel;
  out SourceArgument: TArgPerChannel;
  out Scale: TScalePerChannel;
  out Disabled: boolean;
  out NeedsConstantColor: boolean;
  out InterpolateAlphaSource: TColorSource);

  { Interpret simple mode name (this is for sure only one mode,
    without any "/" and whitespaces). This handles only the simplest
    modes, that behave the same and are allowed separately for
    both RGB and alpha channel.

    LS passed here must already be lowercase.

    Scale passed here must be initially 1.0. }
  procedure SimpleModeFromString(
    const LS: string;
    out Combine: TCombine;
    out CurrentTextureArgument, SourceArgument: TTextureEnvArgument;
    var Scale: Single;
    const Channels: string);
  begin
    if LS = 'modulate' then
    begin
      Combine := coModulate;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
    end else
    if LS = 'modulate2x' then
    begin
      Combine := coModulate;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
      Scale := 2;
    end else
    if LS = 'modulate4x' then
    begin
      Combine := coModulate;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
      Scale := 4;
    end else
    if (LS = 'replace') or (LS = 'selectarg1') then
    begin
      { SELECTARG1 is exactly the same as REPLACE.

        Note: don't get confused by X3D spec saying in table 18.3 that
        "REPLACE" takes the Arg2, that's an error, it takes
        from Arg1 to be consistent with other spec words.
        I wrote some remarks about this on
        http://castle-engine.sourceforge.net/x3d_implementation_status.php }

      Combine := coReplace;
      CurrentTextureArgument := ta0;
      SourceArgument := taNone;
    end else
    if LS = 'selectarg2' then
    begin
      Combine := coReplace;
      CurrentTextureArgument := taNone;
      SourceArgument := ta0;
    end else
    if LS = 'add' then
    begin
      Combine := coAdd;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
    end else
    if LS = 'addsigned' then
    begin
      Combine := coAddSigned;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
    end else
    if LS = 'addsigned2x' then
    begin
      Combine := coAddSigned;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
      Scale := 2;
    end else
    if LS = 'subtract' then
    begin
      Combine := coSubtract;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
    end else
    begin
      Combine := coModulate;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
      OnWarning(wtMajor, 'VRML/X3D', Format('Not supported multi-texturing mode "%s" for channels "%s"', [LS, Channels]));
    end;
  end;

  procedure RGBModeFromString(
    const LS: string;
    out Combine: TCombine;
    out CurrentTextureArgument, SourceArgument: TTextureEnvArgument;
    var Scale: Single);
  begin
    if LS = 'dotproduct3' then
    begin
      { We use DOT3_RGB_ARB here.
        This means it will fill only RGB values.

        This is our extension (X3D spec allows only DOTPRODUCT3
        for both channels, and to fill them both, this case is handled
        in BothModesFromString). }
      Combine := coDot3Rgb;
      CurrentTextureArgument := ta0;
      SourceArgument := ta1;
    end else
      SimpleModeFromString(LS, Combine, CurrentTextureArgument, SourceArgument, Scale, 'RGB');
  end;

  procedure AlphaModeFromString(
    const LS: string;
    out Combine: TCombine;
    out CurrentTextureArgument, SourceArgument: TTextureEnvArgument;
    var Scale: Single);
  begin
    SimpleModeFromString(LS, Combine, CurrentTextureArgument, SourceArgument, Scale, 'Alpha');
  end;

  procedure BothModesFromString(
    const LS: string;
    out Combine: TCombinePerChannel;
    out CurrentTextureArgument, SourceArgument: TArgPerChannel;
    var Scale: TScalePerChannel);
  begin
    if LS = '' then
    begin
      { LS = '' means that mode list was too short.
        X3D spec says explicitly that default mode is "MODULATE"
        in this case. (Accidentaly, this also will accept
        explict "" string as "MODULATE" --- not a worry, we don't
        have to produce error messages for all possible invalid VRMLs...). }

      Combine := CombinePerChannel(coModulate);
      CurrentTextureArgument := ArgPerChannel(ta0);
      SourceArgument := ArgPerChannel(ta1);
    end else
    if LS = 'off' then
    begin
      Disabled := true;
    end else
    if LS = 'dotproduct3' then
    begin
      { We use DOT3_RGBA_ARB, not DOT3_RGB_ARB.
        See [http://www.opengl.org/registry/specs/ARB/texture_env_dot3.txt].

        This means that the dot (done on only RGB channels) will
        be replicated to all four channels (RGBA). This is exactly what
        the X3D specification requires, so we're happy.
        Yes, this means that COMBINE_ALPHA_ARB will be ignored. }

      Combine := CombinePerChannel(coDot3Rgba,
        coReplace { <- whatever, alpha combine will be ignored });
      CurrentTextureArgument := ArgPerChannel(ta0);
      SourceArgument := ArgPerChannel(ta1);
    end else
    if LS = 'blenddiffusealpha' then
    begin
      Combine := CombinePerChannel(coInterpolate);
      CurrentTextureArgument := ArgPerChannel(ta0);
      SourceArgument := ArgPerChannel(ta1);
      InterpolateAlphaSource := csMaterial;
    end else
    if LS = 'blendtexturealpha' then
    begin
      Combine := CombinePerChannel(coInterpolate);
      CurrentTextureArgument := ArgPerChannel(ta0);
      SourceArgument := ArgPerChannel(ta1);
      InterpolateAlphaSource := csCurrentTexture;
    end else
    if LS = 'blendfactoralpha' then
    begin
      Combine := CombinePerChannel(coInterpolate);
      CurrentTextureArgument := ArgPerChannel(ta0);
      SourceArgument := ArgPerChannel(ta1);
      InterpolateAlphaSource := csConstant;
      NeedsConstantColor := true;
    end else
    if LS = 'blendcurrentalpha' then
    begin
      Combine := CombinePerChannel(coInterpolate);
      CurrentTextureArgument := ArgPerChannel(ta0);
      SourceArgument := ArgPerChannel(ta1);
      InterpolateAlphaSource := csPreviousTexture;
    end else
    begin
      SimpleModeFromString(LS,
        Combine[cRGB], CurrentTextureArgument[cRGB], SourceArgument[cRGB], Scale[cRGB], 'both RGB and Alpha');
      Combine               [cAlpha] := Combine               [cRGB];
      CurrentTextureArgument[cAlpha] := CurrentTextureArgument[cRGB];
      SourceArgument        [cAlpha] := SourceArgument        [cRGB];
      Scale                 [cAlpha] := Scale                 [cRGB];
    end;
  end;

var
  LS: string;
  StringPerChannel: TStringPerChannel;
begin
  { initialize some out parameters to default values }
  Disabled := false;
  Scale[cRGB] := 1;
  Scale[cAlpha] := 1;
  NeedsConstantColor := false;
  InterpolateAlphaSource := csMaterial; { unused, will define to be safe }

  LS := LowerCase(S);
  if SplitStringPerChannel(LS, StringPerChannel) then
  begin
    RGBModeFromString  (StringPerChannel[cRGB  ], Combine[cRGB  ], CurrentTextureArgument[cRGB  ], SourceArgument[cRGB  ], Scale[cRGB  ]);
    AlphaModeFromString(StringPerChannel[cAlpha], Combine[cAlpha], CurrentTextureArgument[cAlpha], SourceArgument[cAlpha], Scale[cAlpha]);
  end else
    BothModesFromString(LS, Combine, CurrentTextureArgument, SourceArgument, Scale);
end;

{ Calculate values knowing MultiTexture.source value. }
procedure SourceFromString(const S: string; out Source: TSourcePerChannel;
  var NeedsConstantColor: boolean);

  procedure SimpleSourceFromString(const LS: string;
    out Source: TColorSource;
    var NeedsConstantColor: boolean);
  begin
    if LS = '' then
      Source := csPreviousTexture else
    if (LS = 'diffuse') or (LS = 'specular') then
      Source := csMaterial else
    if LS = 'factor' then
    begin
      NeedsConstantColor := true;
      Source := csConstant;
    end else
    begin
      Source := csPreviousTexture;
      OnWarning(wtMajor, 'VRML/X3D', Format('Not supported multi-texturing source "%s"', [LS]))
    end;
  end;

var
  LS: string;
  SourcePerChannel: TStringPerChannel;
begin
  LS := LowerCase(S);
  if SplitStringPerChannel(LS, SourcePerChannel) then
  begin
    SimpleSourceFromString(SourcePerChannel[cRGB  ], Source[cRGB  ], NeedsConstantColor);
    SimpleSourceFromString(SourcePerChannel[cAlpha], Source[cAlpha], NeedsConstantColor);
  end else
  begin
    SimpleSourceFromString(LS, Source[cRGB], NeedsConstantColor);
    Source[cAlpha] := Source[cRGB];
  end;
end;

{ Convert MultiTexture.function string to TTextureFunction. }
function FunctionFromString(const S: string): TTextureFunction;
var
  LS: string;
begin
  LS := LowerCase(S);
  if LS = '' then
    Result := tfNone else
  if LS = 'complement' then
    Result := tfComplement else
  if LS = 'alphareplicate' then
    Result := tfAlphaReplicate else
  begin
    Result := tfNone;
    OnWarning(wtMajor, 'VRML/X3D', Format('Invalid multi-texturing function "%s"', [S]));
  end;
end;

constructor TTextureEnv.Init(const Mode, SourceStr, FunctionStr: string);
begin
  ModeFromString(Mode, Combine, CurrentTextureArgument, SourceArgument, Scale, Disabled,
    NeedsConstantColor, InterpolateAlphaSource);
  if (SourceArgument[cRGB] <> taNone) or
     (SourceArgument[cAlpha] <> taNone) then
    SourceFromString(SourceStr, Source, NeedsConstantColor);
  TextureFunction := FunctionFromString(FunctionStr);
end;

constructor TTextureEnv.Init(const Mode: TCombine);
begin
  Combine := CombinePerChannel(Mode);

  { constant default values for other fields }
  CurrentTextureArgument := ArgPerChannel(ta0);
  SourceArgument := ArgPerChannel(ta1);
  Scale[cRGB  ] := 1.0;
  Scale[cAlpha] := 1.0;
  Disabled := false;
  NeedsConstantColor := false;
  InterpolateAlphaSource := csMaterial;
  Source[cRGB  ] := csMaterial;
  Source[cAlpha] := csMaterial;
  TextureFunction := tfNone;
end;

function TTextureEnv.Hash: LongWord;
{$include norqcheckbegin.inc}
begin
  Result :=
    1693 * (1 + Ord(Combine[cRGB]                 )) +
    1697 * (1 + Ord(Combine[cAlpha]               )) +
    1699 * (1 + Ord(CurrentTextureArgument[cRGB]  )) +
    1709 * (1 + Ord(CurrentTextureArgument[cAlpha])) +
    1721 * (1 + Ord(SourceArgument[cRGB]          )) +
    1723 * (1 + Ord(SourceArgument[cAlpha]        )) +
    1733 * (1 + Round(Scale[cRGB] * 100           )) +
    1741 * (1 + Round(Scale[cAlpha] * 100         )) +
    1747 * (1 + Ord(Disabled                      )) +
    1753 * (1 + Ord(NeedsConstantColor            )) +
    1759 * (1 + Ord(Source[cRGB]                  )) +
    1777 * (1 + Ord(Source[cAlpha]                )) +
    1783 * (1 + Ord(InterpolateAlphaSource        )) +
    1787 * (1 + Ord(TextureFunction               ));
end;
{$include norqcheckend.inc}

end.