source: trunk/Packages/bgrabitmap/bgraopengl3d.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 29.8 KB
Line 
1unit BGRAOpenGL3D;
2
3{$mode objfpc}{$H+}
4
5interface
6
7uses BGRABitmapTypes,
8 BGRASceneTypes, BGRASSE,
9 Classes, BGRAMatrix3D,
10 BGRACanvasGL,
11 BGRAScene3D,
12 BGRAOpenGLType,
13 BGRATransform,
14 BGRARenderer3D;
15
16type
17 TAttributeVariable = BGRACanvasGL.TAttributeVariable;
18
19 TBGLShader3D = class;
20
21 { TBGLLighting3D }
22
23 TBGLLighting3D = class
24 private
25 procedure SetUseBuiltIn(AValue: boolean);
26 protected
27 FCanvas: TBGLCustomCanvas;
28 FLights: TList;
29 FAmbiantLight: TColorF;
30 FShaderLightingCode: string;
31 FUseBuiltIn: boolean;
32 procedure Init;
33 public
34 constructor Create(ACanvas: TBGLCustomCanvas; AAmbiantLight: TColorF; ALights: TList);
35 procedure SetSpecularIndex(AIndex: Integer);
36 destructor Destroy; override;
37 property ShaderLightingCode: string read FShaderLightingCode;
38 property UseOpenGLBuiltInLighting: boolean read FUseBuiltIn write SetUseBuiltIn;
39 end;
40
41 { TBGLRenderer3D }
42
43 TBGLRenderer3D = class(TCustomRenderer3D)
44 protected
45 FCanvas: TBGLCustomCanvas;
46 FHasZBuffer: Boolean;
47 FGlobalScale: single;
48 FOptions: TRenderingOptions;
49 FFactorZ, FAddZ: single;
50 FLightingGL: TBGLLighting3D;
51 FLights: TList;
52 FAmbiantLight: TColorF;
53 FFar: single;
54 FOldCulling: TFaceCulling;
55 FOldMatrix: TAffineMatrix;
56 FOldProjection, FProjectionMatrix: TMatrix4D;
57 FShader, FShaderWithTexture: TBGLCustomShader;
58 FBGRAShader: TBGRAShader3D;
59 FShadedColorsF: array of TColorF;
60 FShadedColors: array of TBGRAPixel;
61 function GetHasZBuffer: boolean; override;
62 function GetGlobalScale: single; override;
63 function GetSurfaceWidth: integer; override;
64 function GetSurfaceHeight: integer; override;
65 procedure SetProjection(const AValue: TProjection3D); override;
66 function GetHandlesNearClipping: boolean; override;
67 function GetHandlesFaceCulling: boolean; override;
68 procedure InitLighting(AUseOpenGLBuiltInLighting: boolean);
69 public
70 constructor Create(ACanvas: TBGLCustomCanvas;
71 AScene: TBGRAScene3D; AFar: single);
72 function RenderFace(var ADescription: TFaceRenderingDescription;
73 {%H-}AComputeCoordinate: TComputeProjectionFunc): boolean; override;
74 destructor Destroy; override;
75 property Canvas: TBGLCustomCanvas read FCanvas;
76 end;
77
78 { TBGLScene3D }
79
80 TBGLScene3D = class(TBGRAScene3D)
81 protected
82 function LoadBitmapFromFileUTF8(AFilenameUTF8: string): TBGRACustomBitmap; override;
83 public
84 procedure RenderGL(ACanvas: TBGLCustomCanvas; AMaxZ: single = 1000); virtual;
85 end;
86
87 { TUniformVariable }
88
89 TUniformVariable = object
90 private
91 FProgram: TBGLShader3D;
92 FVariable: DWord;
93 procedure Init(AProgram: TBGLShader3D; AVariable: DWord);
94 end;
95
96 { TUniformVariableSingle }
97
98 TUniformVariableSingle = object(TUniformVariable)
99 private
100 FValue: single;
101 procedure SetValue(const AValue: single);
102 public
103 procedure Update;
104 property Value: single read FValue write SetValue;
105 end;
106
107 { TUniformVariablePointF }
108
109 TUniformVariablePointF = object(TUniformVariable)
110 private
111 FValue: TPointF;
112 procedure SetValue(const AValue: TPointF);
113 public
114 procedure Update;
115 property Value: TPointF read FValue write SetValue;
116 end;
117
118 { TUniformVariablePoint3D }
119
120 TUniformVariablePoint3D = object(TUniformVariable)
121 private
122 FValue: TPoint3D;
123 procedure SetValue(const AValue: TPoint3D);
124 public
125 procedure Update;
126 property Value: TPoint3D read FValue write SetValue;
127 end;
128
129 { TUniformVariableInteger }
130
131 TUniformVariableInteger = object(TUniformVariable)
132 private
133 FValue: Integer;
134 procedure SetValue(const AValue: Integer);
135 public
136 procedure Update;
137 property Value: Integer read FValue write SetValue;
138 end;
139
140 { TUniformVariablePoint }
141
142 TUniformVariablePoint = object(TUniformVariable)
143 private
144 FValue: TPoint;
145 procedure SetValue(const AValue: TPoint);
146 public
147 procedure Update;
148 property Value: TPoint read FValue write SetValue;
149 end;
150
151 { TUniformVariableMatrix4D }
152
153 TUniformVariableMatrix4D = object(TUniformVariable)
154 private
155 FValue: TMatrix4D;
156 procedure SetValue(const AValue: TMatrix4D);
157 public
158 procedure Update;
159 property Value: TMatrix4D read FValue write SetValue;
160 end;
161
162 { TAttributeVariableSingle }
163
164 TAttributeVariableSingle = object(TAttributeVariable)
165 protected
166 procedure Init(AProgram: TObject; AAttribute: DWord);
167 end;
168
169 { TAttributeVariablePointF }
170
171 TAttributeVariablePointF = object(TAttributeVariable)
172 protected
173 procedure Init(AProgram: TObject; AAttribute: DWord);
174 end;
175
176 { TAttributeVariablePoint3D }
177
178 TAttributeVariablePoint3D = object(TAttributeVariable)
179 protected
180 procedure Init(AProgram: TObject; AAttribute: DWord);
181 end;
182
183 { TAttributeVariableInteger }
184
185 TAttributeVariableInteger = object(TAttributeVariable)
186 protected
187 procedure Init(AProgram: TObject; AAttribute: DWord);
188 end;
189
190 { TAttributeVariablePoint }
191
192 TAttributeVariablePoint = object(TAttributeVariable)
193 protected
194 procedure Init(AProgram: TObject; AAttribute: DWord);
195 end;
196
197 { TBGLShader3D }
198
199 TBGLShader3D = class(TBGLCustomShader)
200 protected
201 FUsed: boolean;
202 FCanvas: TBGLCustomCanvas;
203 FLighting: TBGLCustomLighting;
204 FVertexShaderSource,
205 FFragmentShaderSource: string;
206 FVertexShader,
207 FFragmentShader,
208 FProgram: DWord;
209 function GetUniformVariableSingle(AName: string): TUniformVariableSingle;
210 function GetUniformVariablePointF(AName: string): TUniformVariablePointF;
211 function GetUniformVariablePoint3D(AName: string): TUniformVariablePoint3D;
212 function GetUniformVariableInteger(AName: string): TUniformVariableInteger;
213 function GetUniformVariablePoint(AName: string): TUniformVariablePoint;
214 function GetUniformVariableMatrix4D(AName: string): TUniformVariableMatrix4D;
215 function GetAttributeVariableInteger(AName: string): TAttributeVariableInteger;
216 function GetAttributeVariablePoint(AName: string): TAttributeVariablePoint;
217 function GetAttributeVariableSingle(AName: string): TAttributeVariableSingle;
218 function GetAttributeVariablePointF(AName: string): TAttributeVariablePointF;
219 function GetAttributeVariablePoint3D(AName: string): TAttributeVariablePoint3D;
220 procedure SetUniformSingle(AVariable: DWord; const AValue; AElementCount: integer; AComponentCount: integer);
221 procedure SetUniformInteger(AVariable: DWord; const AValue; AElementCount: integer; AComponentCount: integer);
222 procedure CheckUsage(AUsing: boolean);
223 procedure StartUse; override;
224 procedure EndUse; override;
225 property Canvas: TBGLCustomCanvas read FCanvas;
226 public
227 constructor Create(ACanvas: TBGLCustomCanvas; AVertexShaderSource: string;
228 AFragmentShaderSource: string; AVaryingVariables: string = '';
229 AVersion: string = '120');
230 destructor Destroy; override;
231 property UniformSingle[AName: string]: TUniformVariableSingle read GetUniformVariableSingle;
232 property UniformPointF[AName: string]: TUniformVariablePointF read GetUniformVariablePointF;
233 property UniformPoint3D[AName: string]: TUniformVariablePoint3D read GetUniformVariablePoint3D;
234 property UniformInteger[AName: string]: TUniformVariableInteger read GetUniformVariableInteger;
235 property UniformPoint[AName: string]: TUniformVariablePoint read GetUniformVariablePoint;
236 property UniformMatrix4D[AName: string]: TUniformVariableMatrix4D read GetUniformVariableMatrix4D;
237 property AttributeSingle[AName: string]: TAttributeVariableSingle read GetAttributeVariableSingle;
238 property AttributePointF[AName: string]: TAttributeVariablePointF read GetAttributeVariablePointF;
239 property AttributePoint3D[AName: string]: TAttributeVariablePoint3D read GetAttributeVariablePoint3D;
240 property AttributeInteger[AName: string]: TAttributeVariableInteger read GetAttributeVariableInteger;
241 property AttributePoint[AName: string]: TAttributeVariablePoint read GetAttributeVariablePoint;
242 property IsUsed: boolean read FUsed;
243 end;
244
245function ProjectionToOpenGL(AProj: TProjection3D; ANear, AFar: Single): TMatrix4D;
246
247implementation
248
249uses SysUtils, BGRAColorInt;
250
251type
252
253 { TShaderWithTexture }
254
255 TShaderWithTexture = class(TBGLShader3D)
256 private
257 function GetTexture: integer;
258 procedure SetTexture(AValue: integer);
259 protected
260 FTextureUniform: TUniformVariableInteger;
261 procedure StartUse; override;
262 public
263 class function GetCodeForTextureColor: string;
264 constructor Create(ACanvas: TBGLCustomCanvas; AFragmentShader: string; ATexture: integer = 0);
265 property Texture: integer read GetTexture write SetTexture;
266 end;
267
268function ProjectionToOpenGL(AProj: TProjection3D; ANear, AFar: Single): TMatrix4D;
269begin
270 result[1,1] := AProj.Zoom.X; result[2,1] := 0; result[3,1] := -(AProj.Center.x + 0.5); result[4,1] := 0;
271 result[1,2] := 0; result[2,2] := AProj.Zoom.Y; result[3,2] := -(AProj.Center.y + 0.5); result[4,2] := 0;
272 result[1,3] := 0; result[2,3] := 0; result[3,3] := -2/(AFar-ANear); result[4,3] := -1 - AFar*result[3,3];
273 result[1,4] := 0; result[2,4] := 0; result[3,4] := -1; result[4,4] := 0;
274end;
275
276{ TUniformVariableMatrix4D }
277
278procedure TUniformVariableMatrix4D.SetValue(const AValue: TMatrix4D);
279begin
280 if CompareMem(@AValue, @FValue, sizeof(FValue)) then Exit;
281 FValue:=AValue;
282 if FProgram.IsUsed then Update;
283end;
284
285procedure TUniformVariableMatrix4D.Update;
286begin
287 FProgram.SetUniformSingle(FVariable, FValue, 1, 16);
288end;
289
290{ TShaderWithTexture }
291
292function TShaderWithTexture.GetTexture: integer;
293begin
294 result := FTextureUniform.Value;
295end;
296
297procedure TShaderWithTexture.SetTexture(AValue: integer);
298begin
299 FTextureUniform.Value := AValue;
300end;
301
302procedure TShaderWithTexture.StartUse;
303begin
304 inherited StartUse;
305 FTextureUniform.Update;
306end;
307
308class function TShaderWithTexture.GetCodeForTextureColor: string;
309begin
310 result := 'texture2D(texture, texture_coordinate)';
311end;
312
313constructor TShaderWithTexture.Create(ACanvas: TBGLCustomCanvas;
314 AFragmentShader: string; ATexture: integer);
315begin
316 inherited Create(ACanvas,
317 'void main(void) ' +
318 '{ ' +
319 ' gl_Position = gl_ProjectionMatrix * gl_Vertex; ' +
320 ' texture_coordinate = vec2(gl_MultiTexCoord0); ' +
321 ' N = gl_Normal; ' +
322 ' V = vec3(gl_Vertex); ' +
323 '} ',
324
325 'uniform sampler2D texture; ' +
326 AFragmentShader,
327
328 'varying vec2 texture_coordinate; ' +
329 'varying vec3 N; ' +
330 'varying vec3 V; ');
331 FTextureUniform := UniformInteger['texture'];
332 Texture := ATexture;
333end;
334
335{ TAttributeVariablePoint3D }
336
337procedure TAttributeVariablePoint3D.Init(AProgram: TObject; AAttribute: DWord);
338begin
339 inherited Init(AProgram,AAttribute,3,True);
340end;
341
342{ TAttributeVariablePointF }
343
344procedure TAttributeVariablePointF.Init(AProgram: TObject; AAttribute: DWord);
345begin
346 inherited Init(AProgram,AAttribute,2,True);
347end;
348
349{ TAttributeVariableInteger }
350
351procedure TAttributeVariableInteger.Init(AProgram: TObject; AAttribute: DWord);
352begin
353 inherited Init(AProgram,AAttribute,1,False);
354end;
355
356{ TAttributeVariablePoint }
357
358procedure TAttributeVariablePoint.Init(AProgram: TObject; AAttribute: DWord);
359begin
360 inherited Init(AProgram,AAttribute,2,False);
361end;
362
363{ TAttributeVariableSingle }
364
365procedure TAttributeVariableSingle.Init(AProgram: TObject; AAttribute: DWord);
366begin
367 inherited Init(AProgram,AAttribute,1,True);
368end;
369
370{ TUniformVariablePoint }
371
372procedure TUniformVariablePoint.SetValue(const AValue: TPoint);
373begin
374 if (FValue.x=AValue.x) and (FValue.y=AValue.y) then Exit;
375 FValue:=AValue;
376 if FProgram.IsUsed then Update;
377end;
378
379procedure TUniformVariablePoint.Update;
380begin
381 FProgram.SetUniformInteger(FVariable, FValue, 1, 2);
382end;
383
384{ TUniformVariableInteger }
385
386procedure TUniformVariableInteger.SetValue(const AValue: Integer);
387begin
388 if FValue=AValue then Exit;
389 FValue:=AValue;
390 if FProgram.IsUsed then Update;
391end;
392
393procedure TUniformVariableInteger.Update;
394begin
395 FProgram.SetUniformInteger(FVariable, FValue, 1, 1);
396end;
397
398{ TUniformVariablePoint3D }
399
400procedure TUniformVariablePoint3D.SetValue(const AValue: TPoint3D);
401begin
402 if (FValue.x=AValue.x) and (FValue.y=AValue.y) and (FValue.z=AValue.z) then Exit;
403 FValue:=AValue;
404 if FProgram.IsUsed then Update;
405end;
406
407procedure TUniformVariablePoint3D.Update;
408begin
409 FProgram.SetUniformSingle(FVariable, FValue, 1, 3);
410end;
411
412{ TUniformVariablePointF }
413
414procedure TUniformVariablePointF.SetValue(const AValue: TPointF);
415begin
416 if (FValue.x=AValue.x) and (FValue.y=AValue.y) then Exit;
417 FValue:=AValue;
418 if FProgram.IsUsed then Update;
419end;
420
421procedure TUniformVariablePointF.Update;
422begin
423 FProgram.SetUniformSingle(FVariable, FValue, 1, 2);
424end;
425
426{ TUniformVariableSingle }
427
428procedure TUniformVariableSingle.SetValue(const AValue: single);
429begin
430 if FValue=AValue then Exit;
431 FValue:=AValue;
432 if FProgram.IsUsed then Update;
433end;
434
435procedure TUniformVariableSingle.Update;
436begin
437 FProgram.SetUniformSingle(FVariable, FValue, 1, 1);
438end;
439
440{ TUniformVariable }
441
442procedure TUniformVariable.Init(AProgram: TBGLShader3D; AVariable: DWord);
443begin
444 FProgram := AProgram;
445 FVariable := AVariable;
446end;
447
448{ TBGLShader3D }
449
450function TBGLShader3D.GetUniformVariableSingle(AName: string): TUniformVariableSingle;
451begin
452 {$push}{$hints off}
453 fillchar(result,sizeof(result),0);
454 result.Init(self, FCanvas.Lighting.GetUniformVariable(FProgram, AName));
455 {$pop}
456end;
457
458function TBGLShader3D.GetUniformVariablePointF(AName: string): TUniformVariablePointF;
459begin
460 {$push}{$hints off}
461 fillchar(result,sizeof(result),0);
462 result.Init(self, FCanvas.Lighting.GetUniformVariable(FProgram, AName));
463 {$pop}
464end;
465
466function TBGLShader3D.GetUniformVariablePoint3D(AName: string): TUniformVariablePoint3D;
467begin
468 {$push}{$hints off}
469 fillchar(result,sizeof(result),0);
470 result.Init(self, FCanvas.Lighting.GetUniformVariable(FProgram, AName));
471 {$pop}
472end;
473
474function TBGLShader3D.GetUniformVariableInteger(AName: string): TUniformVariableInteger;
475begin
476 {$push}{$hints off}
477 fillchar(result,sizeof(result),0);
478 result.Init(self, FCanvas.Lighting.GetUniformVariable(FProgram, AName));
479 {$pop}
480end;
481
482function TBGLShader3D.GetUniformVariablePoint(AName: string): TUniformVariablePoint;
483begin
484 {$push}{$hints off}
485 fillchar(result,sizeof(result),0);
486 result.Init(self, FCanvas.Lighting.GetUniformVariable(FProgram, AName));
487 {$pop}
488end;
489
490function TBGLShader3D.GetUniformVariableMatrix4D(AName: string): TUniformVariableMatrix4D;
491begin
492 {$push}{$hints off}
493 fillchar(result,sizeof(result),0);
494 result.Init(self, FCanvas.Lighting.GetUniformVariable(FProgram, AName));
495 {$pop}
496end;
497
498procedure TBGLShader3D.CheckUsage(AUsing: boolean);
499begin
500 if AUsing <> FUsed then
501 begin
502 if FUsed then raise exception.Create('Shader is in use') else
503 raise exception.Create('Shader is not in use');
504 end;
505end;
506
507function TBGLShader3D.GetAttributeVariableSingle(AName: string): TAttributeVariableSingle;
508begin
509 {$push}{$hints off}
510 fillchar(result,sizeof(result),0);
511 result.Init(self, FCanvas.Lighting.GetAttribVariable(FProgram, AName));
512 {$pop}
513end;
514
515function TBGLShader3D.GetAttributeVariablePointF(AName: string): TAttributeVariablePointF;
516begin
517 {$push}{$hints off}
518 fillchar(result,sizeof(result),0);
519 result.Init(self, FCanvas.Lighting.GetAttribVariable(FProgram, AName));
520 {$pop}
521end;
522
523function TBGLShader3D.GetAttributeVariablePoint3D(AName: string): TAttributeVariablePoint3D;
524begin
525 {$push}{$hints off}
526 fillchar(result,sizeof(result),0);
527 result.Init(self, FCanvas.Lighting.GetAttribVariable(FProgram, AName));
528 {$pop}
529end;
530
531function TBGLShader3D.GetAttributeVariableInteger(AName: string): TAttributeVariableInteger;
532begin
533 {$push}{$hints off}
534 fillchar(result,sizeof(result),0);
535 result.Init(self, FCanvas.Lighting.GetAttribVariable(FProgram, AName));
536 {$pop}
537end;
538
539function TBGLShader3D.GetAttributeVariablePoint(AName: string): TAttributeVariablePoint;
540begin
541 {$push}{$hints off}
542 fillchar(result,sizeof(result),0);
543 result.Init(self, FCanvas.Lighting.GetAttribVariable(FProgram, AName));
544 {$pop}
545end;
546
547procedure TBGLShader3D.SetUniformSingle(AVariable: DWord; const AValue; AElementCount: integer; AComponentCount: integer);
548begin
549 CheckUsage(True);
550 FCanvas.Lighting.SetUniformSingle(AVariable, AValue, AElementCount, AComponentCount);
551end;
552
553procedure TBGLShader3D.SetUniformInteger(AVariable: DWord; const AValue; AElementCount: integer; AComponentCount: integer);
554begin
555 CheckUsage(True);
556 FCanvas.Lighting.SetUniformInteger(AVariable, AValue, AElementCount, AComponentCount);
557end;
558
559constructor TBGLShader3D.Create(ACanvas: TBGLCustomCanvas;
560 AVertexShaderSource: string; AFragmentShaderSource: string;
561 AVaryingVariables: string; AVersion: string);
562begin
563 FCanvas := ACanvas;
564 FLighting := FCanvas.Lighting;
565 FVertexShaderSource:= '#version ' + AVersion + #10 + AVaryingVariables + #10 + AVertexShaderSource;
566 FFragmentShaderSource:= '#version ' + AVersion + #10 + AVaryingVariables + #10 + AFragmentShaderSource;
567 FVertexShader := 0;
568 FFragmentShader := 0;
569 FProgram := 0;
570 try
571 FVertexShader := FLighting.MakeVertexShader(FVertexShaderSource);
572 FFragmentShader := FLighting.MakeFragmentShader(FFragmentShaderSource);
573 FProgram := FLighting.MakeShaderProgram(FVertexShader,FFragmentShader);
574 except on ex:Exception do
575 begin
576 FLighting.DeleteShaderProgram(FProgram);
577 FLighting.DeleteShaderObject(FFragmentShader);
578 FLighting.DeleteShaderObject(FVertexShader);
579 raise ex;
580 end;
581 end;
582end;
583
584destructor TBGLShader3D.Destroy;
585begin
586 if IsUsed then raise exception.Create('Shader is still in use');
587 inherited Destroy;
588end;
589
590procedure TBGLShader3D.StartUse;
591begin
592 CheckUsage(False);
593 FLighting.UseProgram(FProgram);
594 FUsed:= True;
595end;
596
597procedure TBGLShader3D.EndUse;
598begin
599 CheckUsage(True);
600 FLighting.UseProgram(0);
601 FUsed:= False;
602end;
603
604{ TBGLLighting3D }
605
606procedure TBGLLighting3D.SetUseBuiltIn(AValue: boolean);
607begin
608 if FUseBuiltIn=AValue then Exit;
609 FUseBuiltIn:=AValue;
610 FCanvas.Lighting.BuiltInLightingEnabled := FUseBuiltIn;
611end;
612
613procedure TBGLLighting3D.Init;
614var
615 i: Integer;
616 v: TPoint3D;
617 int: single;
618 num: string;
619 minInt: string;
620 colorMult: TColorF;
621begin
622 FShaderLightingCode:=
623 'void main(void) ' +
624 '{ ' +
625 ' vec3 L, H; float d; float sat, sumUnsat; vec4 color, clampedColor; vec4 unsat; ' +
626 ' vec3 Idiff = vec3(gl_LightModel.ambient); ' +
627 ' vec4 Ispec = vec4(0,0,0,0); ' +
628 ' vec3 NN = normalize(N); ';
629 with FCanvas.Lighting do
630 begin
631 AmbiantLightF := FAmbiantLight;
632 for i := 0 to FLights.Count-1 do
633 with TBGRALight3D(FLights[i]) do
634 begin
635 str(GetMinIntensity,minInt);
636 if IsDirectional then
637 begin
638 v := -GetDirection;
639 v.z := -v.z;
640 num := IntToStr(AddDirectionalLight(GetColorF, v));
641 str(GetMinIntensity,minInt);
642 FShaderLightingCode +=
643 ' L = gl_LightSource['+num+'].position.xyz; ' +
644 ' Idiff += vec3(gl_LightSource['+num+'].diffuse * max(dot(NN,L), '+minInt+') ); ' +
645 ' if (gl_FrontMaterial.shininess > 0) { ' +
646 ' H = normalize(L + vec3(0,0,1)); ' +
647 ' Ispec += gl_LightSource['+num+'].specular * pow(abs(dot(NN,H)), gl_FrontMaterial.shininess*2); ' +
648 ' } ';
649 end
650 else
651 begin
652 int := GetIntensity*0.75;
653 if int > 0 then
654 begin
655 v := GetPosition;
656 v.z := -v.z;
657 colorMult := GetColorF * ColorF(int,int,int,1);
658 num := IntToStr(AddPointLight(colorMult, v, 0,1));
659 str(GetMinIntensity/int,minInt);
660 FShaderLightingCode +=
661 ' L = (gl_LightSource['+num+'].position.xyz - V).xyz; ' +
662 ' d = length(L); ' +
663 ' L *= 1/d; ' +
664 ' Idiff += vec3(gl_LightSource['+num+'].diffuse * max(dot(NN,L)/(d*d), '+minInt+') ); ' +
665 ' if (gl_FrontMaterial.shininess > 0) { ' +
666 ' H = normalize(L + vec3(0,0,1)); ' +
667 ' Ispec += gl_LightSource['+num+'].specular * pow(abs(dot(NN,H))/(d*d), gl_FrontMaterial.shininess*2); ' +
668 ' } ';
669 end;
670 end;
671
672 end;
673 end;
674 FShaderLightingCode +=
675 ' color = #color# * vec4(Idiff,1) + Ispec; ' +
676 ' clampedColor = clamp(color,0,1); ' +
677 ' sat = dot( color - clampedColor, vec4(1) ); ' +
678 ' if (sat > 0) { ' +
679 ' unsat = vec4(1) - clampedColor; ' +
680 ' sumUnsat = unsat[0]+unsat[1]+unsat[2]; ' +
681 ' if (sumUnsat > 0) { ' +
682 ' sat *= max(max(unsat[0],unsat[1]),unsat[2]) / sumUnsat; ' +
683 ' gl_FragColor = clamp(color + vec4(sat,sat,sat,0),0,1); ' +
684 ' } ' +
685 ' else gl_FragColor = clampedColor; ' +
686 ' } ' +
687 ' else gl_FragColor = clampedColor; ' +
688 '} ';
689end;
690
691constructor TBGLLighting3D.Create(ACanvas: TBGLCustomCanvas; AAmbiantLight: TColorF; ALights: TList);
692begin
693 FCanvas := ACanvas;
694 FLights := ALights;
695 FAmbiantLight := AAmbiantLight;
696 Init;
697end;
698
699procedure TBGLLighting3D.SetSpecularIndex(AIndex: Integer);
700begin
701 FCanvas.Lighting.SetSpecularIndex(AIndex);
702end;
703
704destructor TBGLLighting3D.Destroy;
705begin
706 FCanvas.Lighting.SetSpecularIndex(0);
707 FCanvas.Lighting.ClearLights;
708 UseOpenGLBuiltInLighting := false;
709 inherited Destroy;
710end;
711
712{ TBGLScene3D }
713
714function TBGLScene3D.LoadBitmapFromFileUTF8(AFilenameUTF8: string
715 ): TBGRACustomBitmap;
716begin
717 if BGLBitmapFactory <> nil then
718 Result:= BGLBitmapFactory.Create(AFilenameUTF8,True)
719 else
720 result := inherited LoadBitmapFromFileUTF8(AFilenameUTF8);
721end;
722
723procedure TBGLScene3D.RenderGL(ACanvas: TBGLCustomCanvas; AMaxZ: single);
724var
725 renderer: TBGLRenderer3D;
726begin
727 renderer := TBGLRenderer3D.Create(ACanvas, self, AMaxZ);
728 Render(renderer);
729 renderer.Free;
730end;
731
732{ TBGLRenderer3D }
733
734function TBGLRenderer3D.GetHasZBuffer: boolean;
735begin
736 result := FHasZBuffer;
737end;
738
739function TBGLRenderer3D.GetGlobalScale: single;
740begin
741 result := FGlobalScale;
742end;
743
744function TBGLRenderer3D.GetSurfaceWidth: integer;
745begin
746 result := FCanvas.Width;
747end;
748
749function TBGLRenderer3D.GetSurfaceHeight: integer;
750begin
751 result := FCanvas.Height;
752end;
753
754{$PUSH}{$OPTIMIZATION OFF} //avoid internal error 2012090607
755procedure TBGLRenderer3D.SetProjection(const AValue: TProjection3D);
756begin
757 inherited SetProjection(AValue);
758 FProjectionMatrix := ProjectionToOpenGL(AValue, FOptions.MinZ, FFar) *
759 OrthoProjectionToOpenGL(0,0,FCanvas.Width,FCanvas.Height);
760 FCanvas.ProjectionMatrix := FProjectionMatrix;
761end;
762{$POP}
763
764function TBGLRenderer3D.GetHandlesNearClipping: boolean;
765begin
766 result := true;
767end;
768
769function TBGLRenderer3D.GetHandlesFaceCulling: boolean;
770begin
771 result := FShader <> nil;
772end;
773
774procedure TBGLRenderer3D.InitLighting(AUseOpenGLBuiltInLighting: boolean);
775var
776 fragmentShaderCode: string;
777begin
778 if not Assigned(FLightingGL) then
779 begin
780 FLightingGL := TBGLLighting3D.Create(FCanvas, FAmbiantLight, FLights);
781
782 if (FOptions.LightingInterpolation <> liLowQuality) and FCanvas.Lighting.SupportShaders then
783 begin
784 fragmentShaderCode := StringReplace(FLightingGL.ShaderLightingCode, '#color#', 'gl_Color', []);
785 FShader := FCanvas.Lighting.Shader[fragmentShaderCode];
786 if (FShader = nil) and FCanvas.Lighting.SupportShaders then
787 begin
788 FShader := TBGLShader3D.Create(FCanvas,
789 'void main(void) ' +
790 '{ ' +
791 ' gl_Position = gl_ProjectionMatrix * gl_Vertex; ' +
792 ' gl_FrontColor = gl_Color; ' +
793 ' gl_BackColor = gl_Color; ' +
794 ' N = gl_Normal; ' +
795 ' V = vec3(gl_Vertex); ' +
796 '} ',
797
798 fragmentShaderCode,
799
800 'varying vec3 N; ' +
801 'varying vec3 V; ');
802 FCanvas.Lighting.Shader[fragmentShaderCode] := FShader;
803 end;
804
805 fragmentShaderCode := StringReplace(FLightingGL.ShaderLightingCode, '#color#', TShaderWithTexture.GetCodeForTextureColor, []);
806 FShaderWithTexture := FCanvas.Lighting.Shader[fragmentShaderCode];
807 if (FShaderWithTexture = nil) and FCanvas.Lighting.SupportShaders then
808 begin
809 FShaderWithTexture := TShaderWithTexture.Create(FCanvas, fragmentShaderCode, 0);
810 FCanvas.Lighting.Shader[fragmentShaderCode] := FShaderWithTexture;
811 end;
812 end else
813 begin
814 FLightingGL.UseOpenGLBuiltInLighting := AUseOpenGLBuiltInLighting;
815 if not AUseOpenGLBuiltInLighting then
816 FBGRAShader := TBGRAShader3D.Create(FAmbiantLight, FLights);
817 end;
818 end;
819end;
820
821constructor TBGLRenderer3D.Create(ACanvas: TBGLCustomCanvas;
822 AScene: TBGRAScene3D; AFar: single);
823begin
824 FCanvas := ACanvas;
825 FOptions := AScene.RenderingOptions;
826 FLights := AScene.MakeLightList;
827 FAmbiantLight := AScene.AmbiantLightColorF;
828 FGlobalScale:= 1;
829 FHasZBuffer := FOptions.PerspectiveMode = pmZBuffer;
830 FFactorZ := -2/(FFar-FOptions.MinZ);
831 FAddZ := -1 - FFar*FFactorZ;
832 FFar := AFar;
833 if FHasZBuffer then ACanvas.StartZBuffer;
834 FOldCulling:= FCanvas.FaceCulling;
835 FOldMatrix := FCanvas.Matrix;
836 FCanvas.ResetTransform;
837 FOldProjection := FCanvas.ProjectionMatrix;
838 FCanvas.ProjectionMatrix := MatrixIdentity4D;
839
840 FShader := nil;
841 FShaderWithTexture := nil;
842
843 InitLighting(False);
844end;
845
846function TBGLRenderer3D.RenderFace(var ADescription: TFaceRenderingDescription;
847 AComputeCoordinate: TComputeProjectionFunc): boolean;
848var
849 NormalCenter3D,PtCenter3D: TPoint3D_128;
850 ColorCenter: TBGRAPixel;
851
852 procedure ComputeCenter;
853 var j: NativeInt;
854 begin
855 with ADescription do
856 begin
857 PtCenter3D := Point3D_128_Zero;
858 NormalCenter3D := Point3D_128_Zero;
859 for j := 0 to NbVertices-1 do
860 begin
861 PtCenter3D += Positions3D[j];
862 NormalCenter3D += Normals3D[j];
863 end;
864 PtCenter3D *= (1/NbVertices);
865 Normalize3D_128(NormalCenter3D);
866 ColorCenter := MergeBGRA(slice(Colors,NbVertices));
867 end;
868 end;
869
870var tex: IBGLTexture;
871 i,j: NativeInt;
872begin
873 result := true;
874
875 if not ProjectionDefined then
876 raise exception.Create('Projection must be defined before drawing faces');
877
878 If ADescription.Texture <> nil then
879 tex := ADescription.Texture.GetTextureGL as IBGLTexture
880 else
881 tex := nil;
882
883 with ADescription do
884 begin
885 if ADescription.Biface then
886 FCanvas.FaceCulling := fcNone
887 else
888 FCanvas.FaceCulling := fcKeepCW;
889
890 if ADescription.Material.GetSpecularOn then
891 FLightingGL.SetSpecularIndex(ADescription.Material.GetSpecularIndex)
892 else
893 FLightingGL.SetSpecularIndex(0);
894
895 if tex <> nil then
896 begin
897 FCanvas.Lighting.ActiveShader := FShaderWithTexture;
898
899 if Assigned(FBGRAShader) then
900 begin
901 FBGRAShader.Prepare(ADescription);
902
903 if length(FShadedColorsF) < NbVertices then
904 setlength(FShadedColorsF, NbVertices);
905 for i := 0 to NbVertices-1 do
906 FShadedColorsF[i] := BGRAToColorF(ColorIntToBGRA(FBGRAShader.Int65536Apply(Positions3D[i],Normals3D[i],BGRAWhite), true), false);
907
908 for i := 0 to NbVertices-1 do
909 Positions3D[i].z := -Positions3D[i].z;
910
911 if NbVertices = 3 then
912 tex.DrawTriangle(slice(Positions3D,3),slice(TexCoords,3),slice(FShadedColorsF,3))
913 else if NbVertices = 4 then
914 tex.DrawQuad(slice(Positions3D,4),slice(TexCoords,4),slice(FShadedColorsF,4));
915 end else
916 begin
917 for i := 0 to NbVertices-1 do
918 begin
919 Positions3D[i].z := -Positions3D[i].z;
920 Normals3D[i].z := -Normals3D[i].z;
921 end;
922
923 if NbVertices = 3 then
924 tex.DrawTriangle(slice(Positions3D,3),slice(Normals3D,3),slice(TexCoords,3))
925 else if NbVertices = 4 then
926 tex.DrawQuad(slice(Positions3D,4),slice(Normals3D,4),slice(TexCoords,4));
927 end;
928 end
929 else
930 begin
931 FCanvas.Lighting.ActiveShader := FShader;
932
933 if Assigned(FBGRAShader) then
934 begin
935 FBGRAShader.Prepare(ADescription);
936
937 if length(FShadedColors) < NbVertices then
938 setlength(FShadedColors, NbVertices);
939 for i := 0 to NbVertices-1 do
940 FShadedColors[i] := FBGRAShader.Apply(Positions3D[i],Normals3D[i],Colors[i]);
941
942 if NbVertices > 4 then
943 begin
944 ComputeCenter;
945 ColorCenter := FBGRAShader.Apply(PtCenter3D,NormalCenter3D,MergeBGRA(slice(Colors,NbVertices)));
946
947 for i := 0 to NbVertices-1 do
948 Positions3D[i].z := -Positions3D[i].z;
949 PtCenter3D.z := -PtCenter3D.z;
950
951 i := NbVertices-1;
952 for j := 0 to NbVertices-1 do
953 begin
954 FCanvas.FillTrianglesLinearColor(
955 [Positions3D[i],Positions3D[j],PtCenter3D],
956 [FShadedColors[i],FShadedColors[j],ColorCenter]);
957 i := j;
958 end;
959 end else
960 begin
961 for i := 0 to NbVertices-1 do
962 Positions3D[i].z := -Positions3D[i].z;
963
964 if NbVertices = 3 then
965 FCanvas.FillTrianglesLinearColor(slice(Positions3D,3),slice(FShadedColors,3))
966 else if NbVertices = 4 then
967 FCanvas.FillQuadsLinearColor(slice(Positions3D,4),slice(FShadedColors,4));
968 end;
969 end else
970 begin
971 for i := 0 to NbVertices-1 do
972 begin
973 Positions3D[i].z := -Positions3D[i].z;
974 Normals3D[i].z := -Normals3D[i].z;
975 end;
976
977 if NbVertices > 4 then
978 begin
979 ComputeCenter;
980
981 i := NbVertices-1;
982 for j := 0 to NbVertices-1 do
983 begin
984 FCanvas.FillTrianglesLinearColor(
985 [Positions3D[i],Positions3D[j],PtCenter3D],
986 [Normals3D[i],Normals3D[j],NormalCenter3D],
987 [Colors[i],Colors[j],ColorCenter]);
988 i := j;
989 end;
990 end else
991 begin
992 if NbVertices = 3 then
993 FCanvas.FillTrianglesLinearColor(slice(Positions3D,3),slice(Normals3D,3),slice(Colors,3))
994 else if NbVertices = 4 then
995 FCanvas.FillQuadsLinearColor(slice(Positions3D,4),slice(Normals3D,4),slice(Colors,4));
996 end;
997 end;
998 end;
999 end;
1000end;
1001
1002destructor TBGLRenderer3D.Destroy;
1003begin
1004 FreeAndNil(FBGRAShader);
1005 FCanvas.Lighting.ActiveShader := nil;
1006 FCanvas.ProjectionMatrix := FOldProjection;
1007 FCanvas.Matrix := FOldMatrix;
1008 FCanvas.FaceCulling := FOldCulling;
1009 FreeAndNil(FLightingGL);
1010 if FHasZBuffer then FCanvas.EndZBuffer;
1011 FLights.Free;
1012 inherited Destroy;
1013end;
1014
1015
1016end.
Note: See TracBrowser for help on using the repository browser.