source: trunk/Packages/bgrabitmap/bgraopengl.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 47.8 KB
Line 
1unit BGRAOpenGL;
2
3{$mode objfpc}{$H+}
4{$I bgrabitmap.inc}
5
6interface
7
8uses
9 Classes, SysUtils, FPimage, BGRAGraphics,
10 BGRAOpenGLType, BGRASpriteGL, BGRACanvasGL, GL, GLext, GLU, BGRABitmapTypes,
11 BGRAFontGL, BGRASSE, BGRAMatrix3D;
12
13type
14 TBGLCustomCanvas = BGRACanvasGL.TBGLCustomCanvas;
15 TBGLSprite = TBGLDefaultSprite;
16 IBGLTexture = BGRAOpenGLType.IBGLTexture;
17 IBGLFont = BGRAOpenGLType.IBGLFont;
18 IBGLRenderedFont = BGRAFontGL.IBGLRenderedFont;
19 TOpenGLResampleFilter = BGRAOpenGLType.TOpenGLResampleFilter;
20 TOpenGLBlendMode = BGRAOpenGLType.TOpenGLBlendMode;
21 TBGLPath = BGRACanvasGL.TBGLPath;
22 TWaitForGPUOption = BGRAOpenGLType.TWaitForGPUOption;
23 TBGLCustomElementArray = BGRACanvasGL.TBGLCustomElementArray;
24 TBGLCustomArray = BGRACanvasGL.TBGLCustomArray;
25 TOpenGLPrimitive = BGRAOpenGLType.TOpenGLPrimitive;
26 TTextLayout = BGRAGraphics.TTextLayout;
27
28const
29 tlTop = BGRAGraphics.tlTop;
30 tlCenter = BGRAGraphics.tlCenter;
31 tlBottom = BGRAGraphics.tlBottom;
32
33type
34 { TBGLContext }
35
36 TBGLContext = object
37 private
38 function GetHeight: integer;
39 function GetWidth: integer;
40 public
41 Canvas: TBGLCustomCanvas;
42 Sprites: TBGLCustomSpriteEngine;
43 property Width: integer read GetWidth;
44 property Height: integer read GetHeight;
45 end;
46
47 { TBGLFrameBuffer }
48
49 TBGLFrameBuffer = class(TBGLCustomFrameBuffer)
50 protected
51 FHeight: integer;
52 FMatrix: TAffineMatrix;
53 FProjectionMatrix: TMatrix4D;
54 FTexture: IBGLTexture;
55 FFrameBufferId, FRenderBufferId: GLuint;
56 FWidth: integer;
57 FSettingMatrices: boolean;
58 function GetTexture: IBGLTexture; override;
59 function GetHandle: pointer; override;
60 function GetHeight: integer; override;
61 function GetMatrix: TAffineMatrix; override;
62 function GetProjectionMatrix: TMatrix4D; override;
63 function GetWidth: integer; override;
64 procedure SetMatrix(AValue: TAffineMatrix); override;
65 procedure SetProjectionMatrix(AValue: TMatrix4D); override;
66 public
67 constructor Create(AWidth,AHeight: integer);
68 function MakeTextureAndFree: IBGLTexture; override;
69 destructor Destroy; override;
70 end;
71
72const
73 orfBox = BGRAOpenGLType.orfBox;
74 orfLinear = BGRAOpenGLType.orfLinear;
75 obmNormal = BGRAOpenGLType.obmNormal;
76 obmAdd = BGRAOpenGLType.obmAdd;
77 obmMultiply = BGRAOpenGLType.obmMultiply;
78 wfgQueueAllCommands = BGRAOpenGLType.wfgQueueAllCommands;
79 wfgFinishAllCommands = BGRAOpenGLType.wfgFinishAllCommands;
80 opPoints = BGRAOpenGLType.opPoints;
81 opLineStrip = BGRAOpenGLType.opLineStrip;
82 opLineLoop = BGRAOpenGLType.opLineLoop;
83 opLines = BGRAOpenGLType.opLines;
84 opTriangleStrip = BGRAOpenGLType.opTriangleStrip;
85 opTriangleFan = BGRAOpenGLType.opTriangleFan;
86 opTriangles = BGRAOpenGLType.opTriangles;
87
88type
89 { TBGLBitmap }
90
91 TBGLBitmap = class(TBGLCustomBitmap)
92 protected
93 function GetOpenGLMaxTexSize: integer; override;
94 end;
95
96function BGLTexture(ARGBAData: PDWord; AllocatedWidth,AllocatedHeight, ActualWidth,ActualHeight: integer): IBGLTexture; overload;
97function BGLTexture(AFPImage: TFPCustomImage): IBGLTexture; overload;
98function BGLTexture(ABitmap: TBitmap): IBGLTexture; overload;
99function BGLTexture(AWidth, AHeight: integer; Color: TColor): IBGLTexture; overload;
100function BGLTexture(AWidth, AHeight: integer; Color: TBGRAPixel): IBGLTexture; overload;
101function BGLTexture(AFilenameUTF8: string): IBGLTexture; overload;
102function BGLTexture(AFilenameUTF8: string; AWidth, AHeight: integer; AResampleFilter: TResampleFilter = rfBox): IBGLTexture; overload;
103function BGLTexture(AStream: TStream): IBGLTexture; overload;
104
105function BGLSpriteEngine: TBGLCustomSpriteEngine;
106
107function BGLCanvas: TBGLCustomCanvas;
108
109procedure BGLViewPort(AWidth,AHeight: integer); overload;
110procedure BGLViewPort(AWidth,AHeight: integer; AColor: TBGRAPixel); overload;
111
112function BGLFont({%H-}AName: string; {%H-}AEmHeight: integer; {%H-}AStyle: TFontStyles = []): IBGLRenderedFont; overload;
113function BGLFont({%H-}AName: string; {%H-}AEmHeight: integer; {%H-}AColor: TBGRAPixel; {%H-}AStyle: TFontStyles = []): IBGLRenderedFont; overload;
114function BGLFont({%H-}AName: string; {%H-}AEmHeight: integer; {%H-}AColor: TBGRAPixel; {%H-}AOutlineColor: TBGRAPixel; {%H-}AStyle: TFontStyles = []): IBGLRenderedFont; overload;
115function BGLFont({%H-}AName: string; {%H-}AEmHeight: integer; ARenderer: TBGRACustomFontRenderer; ARendererOwned: boolean = true): IBGLRenderedFont; overload;
116
117type
118 { TBGLElementArray }
119
120 TBGLElementArray = class(TBGLCustomElementArray)
121 protected
122 FElements: packed array of GLuint;
123 FBuffer: GLuint;
124 function GetCount: integer; override;
125 public
126 constructor Create(const AElements: array of integer); override;
127 procedure Draw(ACanvas: TBGLCustomCanvas; APrimitive: TOpenGLPrimitive; AAttributes: array of TAttributeVariable); override;
128 destructor Destroy; override;
129 end;
130
131 { TBGLArray }
132
133 TBGLArray = class(TBGLCustomArray)
134 protected
135 FBufferAddress: pointer;
136 FCount: integer;
137 FRecordSize: integer;
138 function GetCount: integer; override;
139 function GetRecordSize: integer; override;
140 public
141 constructor Create(ABufferAddress: Pointer; ACount: integer; ARecordSize: integer); override;
142 destructor Destroy; override;
143 end;
144
145implementation
146
147uses BGRABlurGL, BGRATransform{$IFDEF BGRABITMAP_USE_LCL}, BGRAText, BGRATextFX{$ENDIF};
148
149type
150 TBlendFuncSeparateProc = procedure(sfactorRGB: GLenum; dfactorRGB: GLenum; sfactorAlpha: GLenum; dfactorAlpha: GLenum); {$IFDEF Windows} stdcall; {$ELSE} cdecl; {$ENDIF}
151
152function PrimitiveToOpenGL(AValue: TOpenGLPrimitive): GLenum;
153begin
154 case AValue of
155 opPoints: result := GL_POINTS;
156 opLineStrip: result := GL_LINE_STRIP;
157 opLineLoop: result := GL_LINE_LOOP;
158 opLines: result := GL_LINES;
159 opTriangleStrip: result := GL_TRIANGLE_STRIP;
160 opTriangleFan: result := GL_TRIANGLE_FAN;
161 opTriangles: result := GL_TRIANGLES;
162 else
163 raise exception.Create('Unknown primitive type');
164 end;
165end;
166
167procedure NeedOpenGL2_0;
168begin
169 if glUseProgram = nil then
170 begin
171 if not Load_GL_version_2_0 then
172 raise exception.Create('Cannot load OpenGL 2.0');
173 end;
174end;
175
176function CheckOpenGL2_0: boolean;
177begin
178 if glUseProgram = nil then
179 begin
180 result := Load_GL_version_2_0;
181 end
182 else
183 result := true;
184end;
185
186var
187 BGLCanvasInstance: TBGLCustomCanvas;
188 glBlendFuncSeparate: TBlendFuncSeparateProc;
189 glBlendFuncSeparateFetched: boolean;
190
191const
192 GL_COMBINE_ARB = $8570;
193 GL_COMBINE_RGB_ARB = $8571;
194 GL_SOURCE0_RGB_ARB = $8580;
195 GL_PRIMARY_COLOR_ARB = $8577;
196
197type
198 { TBGLTexture }
199
200 TBGLTexture = class(TBGLCustomTexture)
201 protected
202 FFlipX,FFlipY: Boolean;
203
204 function GetOpenGLMaxTexSize: integer; override;
205 function CreateOpenGLTexture(ARGBAData: PDWord; AAllocatedWidth, AAllocatedHeight, AActualWidth, AActualHeight: integer; RGBAOrder: boolean): TBGLTextureHandle; override;
206 procedure UpdateOpenGLTexture(ATexture: TBGLTextureHandle; ARGBAData: PDWord; AAllocatedWidth, AAllocatedHeight, AActualWidth,AActualHeight: integer; RGBAOrder: boolean); override;
207 class function SupportsBGRAOrder: boolean; override;
208 procedure SetOpenGLTextureSize(ATexture: TBGLTextureHandle; AAllocatedWidth, AAllocatedHeight, AActualWidth, AActualHeight: integer); override;
209 procedure ComputeOpenGLFramesCoord(ATexture: TBGLTextureHandle; FramesX: Integer=1; FramesY: Integer=1); override;
210 function GetOpenGLFrameCount(ATexture: TBGLTextureHandle): integer; override;
211 function GetEmptyTexture: TBGLTextureHandle; override;
212 procedure FreeOpenGLTexture(ATexture: TBGLTextureHandle); override;
213 procedure UpdateGLResampleFilter(ATexture: TBGLTextureHandle; AFilter: TOpenGLResampleFilter); override;
214
215 procedure InternalSetColor(const AColor: TBGRAPixel);
216 procedure DoDrawTriangleOrQuad(const APoints: array of TPointF;
217 const APointsZ: array of Single; const APoints3D: array of TPoint3D_128;
218 const ANormals3D: array of TPoint3D_128; const ATexCoords: array of TPointF;
219 const AColors: array of TColorF); override;
220 procedure DoDraw(pt1,pt2,pt3,pt4: TPointF; AColor: TBGRAPixel);
221 procedure DoStretchDraw(x,y,w,h: single; AColor: TBGRAPixel); override;
222 procedure DoStretchDrawAngle(x,y,w,h,angleDeg: single; rotationCenter: TPointF; AColor: TBGRAPixel); override;
223 procedure DoDrawAffine(Origin, HAxis, VAxis: TPointF; AColor: TBGRAPixel); override;
224 procedure Init(ATexture: TBGLTextureHandle; AWidth,AHeight: integer; AOwned: boolean); override;
225 procedure NotifyInvalidFrameSize; override;
226 procedure NotifyErrorLoadingFile(AFilenameUTF8: string); override;
227
228 function NewEmpty: TBGLCustomTexture; override;
229 function NewFromTexture(ATexture: TBGLTextureHandle; AWidth,AHeight: integer): TBGLCustomTexture; override;
230 function Duplicate: TBGLCustomTexture; override;
231
232 public
233 procedure ToggleFlipX; override;
234 procedure ToggleFlipY; override;
235 procedure Bind(ATextureNumber: integer); override;
236 function FilterBlurMotion(ARadius: single; ABlurType: TRadialBlurType; ADirection: TPointF): IBGLTexture; override;
237 function FilterBlurRadial(ARadius: single; ABlurType: TRadialBlurType): IBGLTexture; override;
238
239 end;
240
241 POpenGLTexture = ^TOpenGLTexture;
242 TOpenGLTexture = record
243 ID: GLuint;
244 AllocatedWidth,AllocatedHeight,ActualWidth,ActualHeight: integer;
245 FramesCoord: array of array[0..3] of TPointF;
246 end;
247
248 { TBGLCanvas }
249
250 TBGLCanvas = class(TBGLCustomCanvas)
251 protected
252 FMatrix: TAffineMatrix;
253 FProjectionMatrix: TMatrix4D;
254 FBlendMode: TOpenGLBlendMode;
255 FLighting: TBGLCustomLighting;
256 FFaceCulling: TFaceCulling;
257
258 function GetLighting: TBGLCustomLighting; override;
259
260 function GetMatrix: TAffineMatrix; override;
261 procedure SetMatrix(const AValue: TAffineMatrix); override;
262 function GetProjectionMatrix: TMatrix4D; override;
263 procedure SetProjectionMatrix(const AValue: TMatrix4D); override;
264
265 function GetFaceCulling: TFaceCulling; override;
266 procedure SetFaceCulling(AValue: TFaceCulling); override;
267
268 procedure InternalSetColor(const AColor: TBGRAPixel); override;
269 procedure InternalSetColorF(const AColor: TColorF); override;
270
271 procedure InternalStartPutPixel(const pt: TPointF); override;
272 procedure InternalStartPolyline(const pt: TPointF); override;
273 procedure InternalStartPolygon(const pt: TPointF); override;
274 procedure InternalStartTriangleFan(const pt: TPointF); override;
275 procedure InternalContinueShape(const pt: TPointF); overload; override;
276
277 procedure InternalContinueShape(const pt: TPoint3D); overload; override;
278 procedure InternalContinueShape(const pt: TPoint3D_128); overload; override;
279 procedure InternalContinueShape(const pt, normal: TPoint3D_128); overload; override;
280
281 procedure InternalEndShape; override;
282
283 procedure InternalStartBlend; override;
284 procedure InternalEndBlend; override;
285
286 procedure InternalStartBlendTriangles; override;
287 procedure InternalStartBlendQuads; override;
288 procedure InternalEndBlendTriangles; override;
289 procedure InternalEndBlendQuads; override;
290
291 procedure EnableScissor(AValue: TRect); override;
292 procedure DisableScissor; override;
293
294 function GetBlendMode: TOpenGLBlendMode; override;
295 procedure SetBlendMode(AValue: TOpenGLBlendMode); override;
296
297 procedure SetActiveFrameBuffer(AValue: TBGLCustomFrameBuffer); override;
298 public
299 destructor Destroy; override;
300 procedure Fill(AColor: TBGRAPixel); override;
301 procedure StartZBuffer; override;
302 procedure EndZBuffer; override;
303 procedure WaitForGPU(AOption: TWaitForGPUOption); override;
304 function GetImage(x, y, w, h: integer): TBGRACustomBitmap; override;
305 function CreateFrameBuffer(AWidth, AHeight: integer): TBGLCustomFrameBuffer; override;
306 end;
307
308 { TBGLLighting }
309
310 TBGLLighting = class(TBGLCustomLighting)
311 protected
312 FLightUsage: array[0..7] of boolean;
313 FCurrentSpecularIndex: single;
314 FAmbiantLightF: TColorF;
315 FBuiltInLighting: boolean;
316 function MakeShaderObject(AShaderType: GLenum; ASource: string): GLuint;
317 function AddLight(AColor: TColorF): integer;
318 function GetSupportShaders: boolean; override;
319 procedure SetAmbiantLightF(AAmbiantLight: TColorF); override;
320 function GetAmbiantLightF: TColorF; override;
321 function GetBuiltInLightingEnabled: boolean; override;
322 procedure SetBuiltInLightingEnabled(AValue: boolean); override;
323 public
324 constructor Create;
325 function AddDirectionalLight(AColor: TColorF; ADirection: TPoint3D): integer; override;
326 function AddPointLight(AColor: TColorF; APosition: TPoint3D; ALinearAttenuation, AQuadraticAttenuation: single): integer; override;
327 procedure ClearLights; override;
328 function RemoveLight(AIndex: integer): boolean; override;
329 procedure SetSpecularIndex(AIndex: integer); override;
330
331 function MakeVertexShader(ASource: string): DWord; override;
332 function MakeFragmentShader(ASource: string): DWord; override;
333 function MakeShaderProgram(AVertexShader, AFragmentShader: DWord): DWord; override;
334 procedure UseProgram(AProgram: DWord); override;
335 procedure DeleteShaderObject(AShader: DWord); override;
336 procedure DeleteShaderProgram(AProgram: DWord); override;
337 function GetUniformVariable(AProgram: DWord; AName: string): DWord; override;
338 function GetAttribVariable(AProgram: DWord; AName: string): DWord; override;
339 procedure SetUniformSingle(AVariable: DWord; const AValue; AElementCount, AComponentCount: integer); override;
340 procedure SetUniformInteger(AVariable: DWord; const AValue; AElementCount, AComponentCount: integer); override;
341 procedure BindAttribute(AAttribute: TAttributeVariable); override;
342 procedure UnbindAttribute(AAttribute: TAttributeVariable); override;
343 end;
344
345{ TBGLFrameBuffer }
346
347procedure TBGLFrameBuffer.SetMatrix(AValue: TAffineMatrix);
348begin
349 if FSettingMatrices then Exit;
350 FSettingMatrices := true;
351 FMatrix:=AValue;
352 if FCanvas <> nil then
353 TBGLCustomCanvas(FCanvas).Matrix := AValue;
354 FSettingMatrices := false;
355end;
356
357function TBGLFrameBuffer.GetMatrix: TAffineMatrix;
358begin
359 result := FMatrix;
360end;
361
362function TBGLFrameBuffer.GetTexture: IBGLTexture;
363begin
364 result := FTexture.FlipY;
365end;
366
367function TBGLFrameBuffer.GetHandle: pointer;
368begin
369 result := @FFrameBufferId;
370end;
371
372function TBGLFrameBuffer.GetHeight: integer;
373begin
374 result := FHeight;
375end;
376
377function TBGLFrameBuffer.GetProjectionMatrix: TMatrix4D;
378begin
379 result := FProjectionMatrix;
380end;
381
382function TBGLFrameBuffer.GetWidth: integer;
383begin
384 result := FWidth;
385end;
386
387procedure TBGLFrameBuffer.SetProjectionMatrix(AValue: TMatrix4D);
388begin
389 if FSettingMatrices then Exit;
390 FSettingMatrices := true;
391 FProjectionMatrix:= AValue;
392 if FCanvas <> nil then
393 TBGLCustomCanvas(FCanvas).ProjectionMatrix := AValue;
394 FSettingMatrices := false;
395end;
396
397constructor TBGLFrameBuffer.Create(AWidth, AHeight: integer);
398var frameBufferStatus: GLenum;
399begin
400 if not Load_GL_version_3_0 then
401 raise exception.Create('Cannot load OpenGL 3.0');
402
403 FWidth := AWidth;
404 FHeight := AHeight;
405
406 FTexture := BGLTextureFactory.Create(nil,AWidth,AHeight,AWidth,AHeight);
407
408 //depth and stencil
409 glGenRenderbuffers(1, @FRenderBufferId);
410 glBindRenderbuffer(GL_RENDERBUFFER, FRenderBufferId);
411 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, AWidth,AHeight);
412 glBindRenderbuffer(GL_RENDERBUFFER, 0);
413
414 glGenFramebuffers(1, @FFrameBufferId);
415 glBindFramebuffer(GL_FRAMEBUFFER, FFrameBufferId);
416
417 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, PGLuint(FTexture.Handle)^, 0);
418 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, FFrameBufferId);
419
420 frameBufferStatus:= glCheckFramebufferStatus(GL_FRAMEBUFFER);
421 glBindFramebuffer(GL_FRAMEBUFFER, 0);
422
423 if frameBufferStatus <> GL_FRAMEBUFFER_COMPLETE then
424 begin
425 glDeleteFramebuffers(1, @FFrameBufferId);
426 glDeleteRenderbuffers(1, @FRenderBufferId);
427 FTexture := nil;
428 raise exception.Create('Error ' + inttostr(frameBufferStatus) + ' while initializing frame buffer');
429 end;
430
431 UseOrthoProjection;
432 Matrix := AffineMatrixIdentity;
433end;
434
435function TBGLFrameBuffer.MakeTextureAndFree: IBGLTexture;
436begin
437 result := FTexture;
438 FTexture := nil;
439 Free;
440end;
441
442destructor TBGLFrameBuffer.Destroy;
443begin
444 glDeleteFramebuffers(1, @FFrameBufferId);
445 glDeleteRenderbuffers(1, @FRenderBufferId);
446 FTexture := nil;
447
448 inherited Destroy;
449end;
450
451procedure ApplyBlendMode(ABlendMode: TOpenGLBlendMode);
452var
453 srcBlend : LongWord;
454 dstBlend : LongWord;
455begin
456 case ABlendMode of
457 obmAdd:
458 begin
459 srcBlend := GL_SRC_ALPHA;
460 dstBlend := GL_ONE;
461 end;
462 obmMultiply:
463 begin
464 srcBlend := GL_ZERO;
465 dstBlend := GL_SRC_COLOR;
466 end
467 else
468 begin
469 srcBlend := GL_SRC_ALPHA;
470 dstBlend := GL_ONE_MINUS_SRC_ALPHA;
471 end;
472 end;
473 if not glBlendFuncSeparateFetched then
474 begin
475 glBlendFuncSeparate := TBlendFuncSeparateProc(wglGetProcAddress('glBlendFuncSeparate'));
476 glBlendFuncSeparateFetched := true;
477 end;
478 if Assigned(glBlendFuncSeparate) then
479 glBlendFuncSeparate( srcBlend, dstBlend, GL_ONE, GL_ONE_MINUS_SRC_ALPHA )
480 else
481 glBlendFunc( srcBlend, dstBlend );
482end;
483
484function BGLTexture(ARGBAData: PDWord; AllocatedWidth, AllocatedHeight,
485 ActualWidth, ActualHeight: integer): IBGLTexture;
486begin
487 result := TBGLTexture.Create(ARGBAData,AllocatedWidth, AllocatedHeight,
488 ActualWidth, ActualHeight);
489end;
490
491function BGLTexture(AFPImage: TFPCustomImage): IBGLTexture;
492begin
493 result := TBGLTexture.Create(AFPImage);
494end;
495
496function BGLTexture(ABitmap: TBitmap): IBGLTexture;
497begin
498 result := TBGLTexture.Create(ABitmap);
499end;
500
501function BGLTexture(AWidth, AHeight: integer; Color: TColor): IBGLTexture;
502begin
503 result := TBGLTexture.Create(AWidth,AHeight,Color);
504end;
505
506function BGLTexture(AWidth, AHeight: integer; Color: TBGRAPixel): IBGLTexture;
507begin
508 result := TBGLTexture.Create(AWidth,AHeight,Color);
509end;
510
511function BGLTexture(AFilenameUTF8: string): IBGLTexture;
512begin
513 result := TBGLTexture.Create(AFilenameUTF8);
514end;
515
516function BGLTexture(AFilenameUTF8: string; AWidth, AHeight: integer; AResampleFilter: TResampleFilter): IBGLTexture;
517begin
518 result := TBGLTexture.Create(AFilenameUTF8, AWidth, AHeight, AResampleFilter);
519end;
520
521function BGLTexture(AStream: TStream): IBGLTexture;
522begin
523 result := TBGLTexture.Create(AStream);
524end;
525
526function BGLSpriteEngine: TBGLCustomSpriteEngine;
527begin
528 result := BGRASpriteGL.BGLSpriteEngine;
529end;
530
531procedure BGLViewPort(AWidth, AHeight: integer; AColor: TBGRAPixel);
532begin
533 BGLViewPort(AWidth,AHeight);
534 BGLCanvas.Fill(AColor);
535end;
536
537function BGLFont(AName: string; AEmHeight: integer; AStyle: TFontStyles = []): IBGLRenderedFont;
538begin
539 {$IFDEF BGRABITMAP_USE_LCL}
540 result := BGLFont(AName, AEmHeight, TLCLFontRenderer.Create);
541 result.Style := AStyle;
542 {$ELSE}
543 result := nil;
544 raise exception.Create('LCL renderer not available');
545 {$ENDIF}
546end;
547
548function BGLFont(AName: string; AEmHeight: integer; AColor: TBGRAPixel;
549 AStyle: TFontStyles): IBGLRenderedFont;
550begin
551 {$IFDEF BGRABITMAP_USE_LCL}
552 result := BGLFont(AName, AEmHeight, TLCLFontRenderer.Create);
553 result.Color := AColor;
554 result.Style := AStyle;
555 {$ELSE}
556 result := nil;
557 raise exception.Create('LCL renderer not available');
558 {$ENDIF}
559end;
560
561function BGLFont(AName: string; AEmHeight: integer; AColor: TBGRAPixel;
562 AOutlineColor: TBGRAPixel; AStyle: TFontStyles = []): IBGLRenderedFont;
563{$IFDEF BGRABITMAP_USE_LCL}
564var renderer: TBGRATextEffectFontRenderer;
565begin
566 renderer := TBGRATextEffectFontRenderer.Create;
567 renderer.OuterOutlineOnly:= true;
568 renderer.OutlineColor := AOutlineColor;
569 renderer.OutlineVisible := true;
570 result := BGLFont(AName, AEmHeight, renderer, true);
571 result.Color := AColor;
572 result.Style := AStyle;
573end;
574{$ELSE}
575begin
576 result := nil;
577 raise exception.Create('LCL renderer not available');
578end;
579{$ENDIF}
580
581function BGLFont(AName: string; AEmHeight: integer;
582 ARenderer: TBGRACustomFontRenderer;
583 ARendererOwned: boolean): IBGLRenderedFont;
584var f: TBGLRenderedFont;
585begin
586 f:= TBGLRenderedFont.Create(ARenderer, ARendererOwned);
587 f.Name := AName;
588 f.EmHeight := AEmHeight;
589 result := f;
590end;
591
592function BGLCanvas: TBGLCustomCanvas;
593begin
594 result := BGLCanvasInstance;
595end;
596
597procedure BGLViewPort(AWidth, AHeight: integer);
598begin
599 BGLCanvas.Width := AWidth;
600 BGLCanvas.Height := AHeight;
601 BGLCanvas.UseOrthoProjection;
602 BGLCanvas.Matrix := AffineMatrixIdentity;
603 BGLCanvas.FaceCulling := fcNone;
604end;
605
606{ TBGLArray }
607
608function TBGLArray.GetCount: integer;
609begin
610 result := FCount;
611end;
612
613function TBGLArray.GetRecordSize: integer;
614begin
615 result := FRecordSize;
616end;
617
618constructor TBGLArray.Create(ABufferAddress: pointer; ACount: integer;
619 ARecordSize: integer);
620var b: GLuint;
621begin
622 NeedOpenGL2_0;
623 FBufferAddress:= ABufferAddress;
624 FCount := ACount;
625 FRecordSize:= ARecordSize;
626 glGenBuffers(1, @b);
627 FBuffer := b;
628 glBindBuffer(GL_ARRAY_BUFFER, FBuffer);
629 glBufferData(GL_ARRAY_BUFFER, FCount*FRecordSize, FBufferAddress, GL_STATIC_DRAW);
630end;
631
632destructor TBGLArray.Destroy;
633var b: GLuint;
634begin
635 b := FBuffer;
636 glDeleteBuffers(1, @b);
637 inherited Destroy;
638end;
639
640{ TBGLElementArray }
641
642function TBGLElementArray.GetCount: integer;
643begin
644 result := length(FElements);
645end;
646
647constructor TBGLElementArray.Create(const AElements: array of integer);
648var bufferSize: integer;
649 i: NativeInt;
650begin
651 NeedOpenGL2_0;
652 setlength(FElements,length(AElements));
653 bufferSize := length(FElements)*sizeof(integer);
654 for i := 0 to high(FElements) do
655 FElements[i] := AElements[i];
656 glGenBuffers(1, @FBuffer);
657 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, FBuffer);
658 glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, @FElements[0], GL_STATIC_DRAW);
659end;
660
661procedure TBGLElementArray.Draw(ACanvas: TBGLCustomCanvas; APrimitive: TOpenGLPrimitive; AAttributes: array of TAttributeVariable);
662var
663 i: NativeInt;
664begin
665 for i := 0 to high(AAttributes) do
666 ACanvas.Lighting.BindAttribute(AAttributes[i]);
667
668 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, FBuffer);
669 glDrawElements(PrimitiveToOpenGL(APrimitive), Count, GL_UNSIGNED_INT, nil);
670
671 for i := 0 to high(AAttributes) do
672 ACanvas.Lighting.UnbindAttribute(AAttributes[i]);
673end;
674
675destructor TBGLElementArray.Destroy;
676begin
677 glDeleteBuffers(1, @FBuffer);
678 inherited Destroy;
679end;
680
681{ TBGLLighting }
682
683procedure TBGLLighting.SetAmbiantLightF(AAmbiantLight: TColorF);
684begin
685 FAmbiantLightF := AAmbiantLight;
686 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, @AAmbiantLight);
687end;
688
689constructor TBGLLighting.Create;
690begin
691 FAmbiantLightF := ColorF(1,1,1,1);
692end;
693
694function TBGLLighting.AddPointLight(AColor: TColorF; APosition: TPoint3D; ALinearAttenuation, AQuadraticAttenuation: single): integer;
695var
696 v: TPoint3D_128;
697begin
698 result := AddLight(AColor);
699 if result <> -1 then
700 begin
701 v := Point3D_128(APosition);
702 v.t := 1;
703 glLightfv(GL_LIGHT0 + result, GL_POSITION, @v);
704 glLightf(GL_LIGHT0 + result, GL_CONSTANT_ATTENUATION, 0);
705 glLightf(GL_LIGHT0 + result, GL_LINEAR_ATTENUATION, ALinearAttenuation);
706 glLightf(GL_LIGHT0 + result, GL_QUADRATIC_ATTENUATION, AQuadraticAttenuation);
707 end;
708end;
709
710procedure TBGLLighting.ClearLights;
711var
712 i: Integer;
713begin
714 for i := 0 to High(FLightUsage) do
715 if FLightUsage[i] then
716 RemoveLight(i);
717end;
718
719function TBGLLighting.AddDirectionalLight(AColor: TColorF; ADirection: TPoint3D): integer;
720var
721 v: TPoint3D_128;
722begin
723 result := AddLight(AColor);
724 if result <> -1 then
725 begin
726 v := Point3D_128(ADirection);
727 Normalize3D_128(v);
728 v.t := 0;
729 glLightfv(GL_LIGHT0 + result, GL_POSITION, @v);
730 end;
731end;
732
733procedure TBGLLighting.SetSpecularIndex(AIndex: integer);
734var c: TColorF;
735 newIndex: single;
736begin
737 newIndex := AIndex*0.5;
738 if newIndex < 0 then newIndex := 0;
739 if newIndex > 128 then newIndex := 128;
740 if newIndex <> FCurrentSpecularIndex then
741 begin
742 if newIndex = 0 then
743 c := ColorF(0,0,0,1)
744 else
745 c := ColorF(1,1,1,1);
746 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, newIndex);
747 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, @c);
748 FCurrentSpecularIndex := newIndex;
749 end;
750end;
751
752function TBGLLighting.MakeVertexShader(ASource: string): DWord;
753begin
754 result := MakeShaderObject(GL_VERTEX_SHADER, ASource);
755end;
756
757function TBGLLighting.MakeFragmentShader(ASource: string): DWord;
758begin
759 result := MakeShaderObject(GL_FRAGMENT_SHADER, ASource);
760end;
761
762function TBGLLighting.GetAmbiantLightF: TColorF;
763begin
764 result := FAmbiantLightF;
765end;
766
767function TBGLLighting.GetBuiltInLightingEnabled: boolean;
768begin
769 result := FBuiltInLighting;
770end;
771
772procedure TBGLLighting.SetBuiltInLightingEnabled(AValue: boolean);
773begin
774 if AValue = FBuiltInLighting then exit;
775 FBuiltInLighting:= AValue;
776 if AValue then
777 begin
778 glEnable(GL_LIGHTING);
779 glShadeModel(GL_SMOOTH);
780 glEnable(GL_COLOR_MATERIAL);
781 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
782 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, @FAmbiantLightF);
783 glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 0);
784 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,1);
785 end else
786 begin
787 glDisable(GL_LIGHTING);
788 end;
789end;
790
791function TBGLLighting.MakeShaderObject(AShaderType: GLenum; ASource: string
792 ): GLuint;
793var
794 psource: pchar;
795 sourceLen: GLint;
796 shaderId: GLuint;
797 shaderOk: GLint;
798 log: string;
799 logLen: GLint;
800begin
801 NeedOpenGL2_0;
802
803 if ASource = '' then
804 raise exception.Create('Empty code file provided');
805
806 shaderId := glCreateShader(AShaderType);
807 psource := @ASource[1];
808 sourceLen := length(ASource);
809 glShaderSource(shaderId, 1, @psource, @sourceLen);
810 glCompileShader(shaderId);
811
812 glGetShaderiv(shaderId, GL_COMPILE_STATUS, @shaderOk);
813 if not (shaderOk <> 0) then
814 begin
815 //retrieve error log
816 glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, @logLen);
817 setlength(log, logLen);
818 if logLen > 0 then
819 glGetShaderInfoLog(shaderId, logLen, nil, @log[1]);
820
821 glDeleteShader(shaderId);
822 raise exception.Create('Failed to compile shader: ' + log);
823 end;
824 result := shaderId;
825end;
826
827function TBGLLighting.AddLight(AColor: TColorF): integer;
828var
829 i: Integer;
830 black: TColorF;
831begin
832 for i := 0 to high(FLightUsage) do
833 if not FLightUsage[i] then
834 begin
835 result := i;
836 FLightUsage[i] := true;
837 black := ColorF(0,0,0,1);
838 glLightfv(GL_LIGHT0 + i, GL_AMBIENT, @black);
839 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, @AColor);
840 glLightfv(GL_LIGHT0 + i, GL_SPECULAR, @AColor);
841 glEnable(GL_LIGHT0 + i);
842 exit;
843 end;
844 result := -1;
845end;
846
847function TBGLLighting.GetSupportShaders: boolean;
848begin
849 result := CheckOpenGL2_0;
850end;
851
852function TBGLLighting.MakeShaderProgram(AVertexShader, AFragmentShader: DWord): DWord;
853var
854 programOk: GLint;
855 shaderProgram: GLuint;
856 log: string;
857 logLen: GLint;
858begin
859 NeedOpenGL2_0;
860
861 shaderProgram := glCreateProgram();
862 glAttachShader(shaderProgram, AVertexShader);
863 glAttachShader(shaderProgram, AFragmentShader);
864 glLinkProgram(shaderProgram);
865
866 glGetProgramiv(shaderProgram, GL_LINK_STATUS, @programOk);
867 if not (programOk <> 0) then
868 begin
869 //retrieve error log
870 glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, @logLen);
871 setlength(log, logLen);
872 if logLen > 0 then
873 glGetProgramInfoLog(shaderProgram, logLen, nil, @log[1]);
874
875 glDeleteProgram(shaderProgram);
876 raise exception.Create('Failed to link shader program: ' + log);
877 end;
878 result := shaderProgram;
879end;
880
881procedure TBGLLighting.UseProgram(AProgram: DWord);
882begin
883 NeedOpenGL2_0;
884 glUseProgram(AProgram);
885end;
886
887procedure TBGLLighting.DeleteShaderObject(AShader: DWord);
888begin
889 NeedOpenGL2_0;
890 if AShader<> 0 then
891 glDeleteShader(AShader);
892end;
893
894procedure TBGLLighting.DeleteShaderProgram(AProgram: DWord);
895begin
896 NeedOpenGL2_0;
897 if AProgram<> 0 then
898 glDeleteProgram(AProgram);
899end;
900
901function TBGLLighting.GetUniformVariable(AProgram: DWord; AName: string): DWord;
902begin
903 NeedOpenGL2_0;
904 result := glGetUniformLocation(AProgram, @AName[1]);
905end;
906
907function TBGLLighting.GetAttribVariable(AProgram: DWord; AName: string): DWord;
908begin
909 NeedOpenGL2_0;
910 result := glGetAttribLocation(AProgram, @AName[1]);
911end;
912
913procedure TBGLLighting.SetUniformSingle(AVariable: DWord;
914 const AValue; AElementCount, AComponentCount: integer);
915begin
916 NeedOpenGL2_0;
917 case AComponentCount of
918 1: glUniform1fv(AVariable, AElementCount, @AValue);
919 2: glUniform2fv(AVariable, AElementCount, @AValue);
920 3: glUniform3fv(AVariable, AElementCount, @AValue);
921 4: glUniform4fv(AVariable, AElementCount, @AValue);
922 9: glUniformMatrix3fv(AVariable, AElementCount, GL_FALSE, @AValue);
923 16: glUniformMatrix4fv(AVariable, AElementCount, GL_FALSE, @AValue);
924 else
925 raise exception.Create('Unexpected number of components');
926 end;
927end;
928
929procedure TBGLLighting.SetUniformInteger(AVariable: DWord;
930 const AValue; AElementCount, AComponentCount: integer);
931begin
932 NeedOpenGL2_0;
933 case AComponentCount of
934 1: glUniform1iv(AVariable, AElementCount, @AValue);
935 2: glUniform2iv(AVariable, AElementCount, @AValue);
936 3: glUniform3iv(AVariable, AElementCount, @AValue);
937 4: glUniform4iv(AVariable, AElementCount, @AValue);
938 else
939 raise exception.Create('Unexpected number of components');
940 end;
941end;
942
943procedure TBGLLighting.BindAttribute(AAttribute: TAttributeVariable);
944var t: GLenum;
945begin
946 glBindBuffer(GL_ARRAY_BUFFER, AAttribute.Source.Handle);
947 if AAttribute.IsFloat then
948 t := GL_FLOAT
949 else
950 t := GL_INT;
951 glVertexAttribPointer(AAttribute.Handle, AAttribute.VectorSize,t,GL_FALSE,
952 AAttribute.Source.RecordSize, {%H-}pointer(PtrInt(AAttribute.RecordOffset)));
953 glEnableVertexAttribArray(AAttribute.Handle);
954end;
955
956procedure TBGLLighting.UnbindAttribute(AAttribute: TAttributeVariable);
957begin
958 glDisableVertexAttribArray(AAttribute.Handle);
959end;
960
961function TBGLLighting.RemoveLight(AIndex: integer): boolean;
962begin
963 if (AIndex >= 0) and (AIndex <= high(FLightUsage)) and
964 FLightUsage[AIndex] then
965 begin
966 glDisable(GL_LIGHT0 + AIndex);
967 FLightUsage[AIndex] := false;
968 result := true;
969 end
970 else
971 result := false;
972end;
973
974{ TBGLContext }
975
976function TBGLContext.GetHeight: integer;
977begin
978 if Assigned(Canvas) then
979 result := Canvas.Height
980 else
981 result := 0;
982end;
983
984function TBGLContext.GetWidth: integer;
985begin
986 if Assigned(Canvas) then
987 result := Canvas.Width
988 else
989 result := 0;
990end;
991
992{ TBGLCanvas }
993
994function TBGLCanvas.GetLighting: TBGLCustomLighting;
995begin
996 if FLighting = nil then
997 FLighting := TBGLLighting.Create;
998 result := FLighting;
999end;
1000
1001function TBGLCanvas.GetMatrix: TAffineMatrix;
1002begin
1003 if ActiveFrameBuffer <> nil then
1004 result := ActiveFrameBuffer.Matrix
1005 else
1006 result := FMatrix;
1007end;
1008
1009procedure TBGLCanvas.SetMatrix(const AValue: TAffineMatrix);
1010var m: TMatrix4D;
1011begin
1012 glMatrixMode(GL_MODELVIEW);
1013 m := AffineMatrixToMatrix4D(AValue);
1014 glLoadMatrixf(@m);
1015
1016 if ActiveFrameBuffer <> nil then
1017 ActiveFrameBuffer.Matrix := AValue
1018 else
1019 FMatrix := AValue;
1020end;
1021
1022function TBGLCanvas.GetProjectionMatrix: TMatrix4D;
1023begin
1024 if ActiveFrameBuffer <> nil then
1025 result := ActiveFrameBuffer.ProjectionMatrix
1026 else
1027 result := FProjectionMatrix;
1028end;
1029
1030procedure TBGLCanvas.SetProjectionMatrix(const AValue: TMatrix4D);
1031begin
1032 glMatrixMode(GL_PROJECTION);
1033 glLoadMatrixf(@AValue);
1034 glMatrixMode(GL_MODELVIEW);
1035
1036 if ActiveFrameBuffer <> nil then
1037 ActiveFrameBuffer.ProjectionMatrix := AValue
1038 else
1039 FProjectionMatrix := AValue;
1040end;
1041
1042function TBGLCanvas.GetFaceCulling: TFaceCulling;
1043begin
1044 result := FFaceCulling;
1045end;
1046
1047procedure TBGLCanvas.SetFaceCulling(AValue: TFaceCulling);
1048begin
1049 if AValue = FFaceCulling then exit;
1050 if FFaceCulling = fcNone then
1051 glEnable(GL_CULL_FACE);
1052 case AValue of
1053 fcNone: glDisable(GL_CULL_FACE);
1054 fcKeepCW: glFrontFace(GL_CW);
1055 fcKeepCCW: glFrontFace(GL_CCW);
1056 end;
1057 FFaceCulling:= AValue;
1058end;
1059
1060procedure TBGLCanvas.InternalStartPutPixel(const pt: TPointF);
1061begin
1062 glBegin(GL_POINTS);
1063 glVertex2fv(@pt);
1064end;
1065
1066procedure TBGLCanvas.InternalStartPolyline(const pt: TPointF);
1067begin
1068 glBegin(GL_LINE_STRIP);
1069 glVertex2fv(@pt);
1070end;
1071
1072procedure TBGLCanvas.InternalStartPolygon(const pt: TPointF);
1073begin
1074 glBegin(GL_LINE_LOOP);
1075 glVertex2fv(@pt);
1076end;
1077
1078procedure TBGLCanvas.InternalStartTriangleFan(const pt: TPointF);
1079begin
1080 glBegin(GL_TRIANGLE_FAN);
1081 glVertex2fv(@pt);
1082end;
1083
1084procedure TBGLCanvas.InternalContinueShape(const pt: TPointF);
1085begin
1086 glVertex2fv(@pt);
1087end;
1088
1089procedure TBGLCanvas.InternalContinueShape(const pt: TPoint3D);
1090begin
1091 glVertex3fv(@pt);
1092end;
1093
1094procedure TBGLCanvas.InternalContinueShape(const pt: TPoint3D_128);
1095begin
1096 glVertex3fv(@pt);
1097end;
1098
1099procedure TBGLCanvas.InternalContinueShape(const pt, normal: TPoint3D_128);
1100begin
1101 glNormal3fv(@normal);
1102 glVertex3fv(@pt);
1103end;
1104
1105procedure TBGLCanvas.InternalEndShape;
1106begin
1107 glEnd();
1108end;
1109
1110procedure TBGLCanvas.InternalSetColor(const AColor: TBGRAPixel);
1111begin
1112 if TBGRAPixel_RGBAOrder then
1113 glColor4ubv(@AColor)
1114 else
1115 glColor4ub(AColor.red,AColor.green,AColor.blue,AColor.alpha);
1116end;
1117
1118procedure TBGLCanvas.InternalSetColorF(const AColor: TColorF);
1119begin
1120 glColor4fv(@AColor[1]);
1121end;
1122
1123procedure TBGLCanvas.InternalStartBlend;
1124begin
1125 glEnable(GL_BLEND);
1126 ApplyBlendMode(BlendMode);
1127end;
1128
1129procedure TBGLCanvas.InternalEndBlend;
1130begin
1131 glDisable(GL_BLEND);
1132end;
1133
1134procedure TBGLCanvas.InternalStartBlendTriangles;
1135begin
1136 InternalStartBlend;
1137 glBegin(GL_TRIANGLES);
1138end;
1139
1140procedure TBGLCanvas.InternalStartBlendQuads;
1141begin
1142 InternalStartBlend;
1143 glBegin(GL_QUADS);
1144end;
1145
1146procedure TBGLCanvas.InternalEndBlendTriangles;
1147begin
1148 InternalEndShape;
1149 InternalEndBlend;
1150end;
1151
1152procedure TBGLCanvas.InternalEndBlendQuads;
1153begin
1154 InternalEndShape;
1155 InternalEndBlend;
1156end;
1157
1158procedure TBGLCanvas.Fill(AColor: TBGRAPixel);
1159begin
1160 glClearColor(AColor.Red/255, AColor.green/255, AColor.blue/255, AColor.alpha/255);
1161 glClear(GL_COLOR_BUFFER_BIT);
1162end;
1163
1164procedure TBGLCanvas.StartZBuffer;
1165begin
1166 glEnable(GL_DEPTH_TEST);
1167 glClear(GL_DEPTH_BUFFER_BIT);
1168end;
1169
1170procedure TBGLCanvas.EndZBuffer;
1171begin
1172 glDisable(GL_DEPTH_TEST);
1173end;
1174
1175procedure TBGLCanvas.WaitForGPU(AOption: TWaitForGPUOption);
1176begin
1177 case AOption of
1178 wfgQueueAllCommands: glFlush;
1179 wfgFinishAllCommands: glFinish;
1180 end;
1181end;
1182
1183function TBGLCanvas.GetImage(x, y, w, h: integer): TBGRACustomBitmap;
1184begin
1185 NeedOpenGL2_0;
1186 result := BGRABitmapFactory.Create(w,h);
1187 if TBGRAPixel_RGBAOrder then
1188 glReadPixels(x,self.Height-y-h, w,h, GL_RGBA, GL_UNSIGNED_BYTE, result.Data)
1189 else
1190 glReadPixels(x,self.Height-y-h, w,h, GL_BGRA, GL_UNSIGNED_BYTE, result.Data);
1191end;
1192
1193function TBGLCanvas.CreateFrameBuffer(AWidth, AHeight: integer): TBGLCustomFrameBuffer;
1194begin
1195 Result:= TBGLFrameBuffer.Create(AWidth,AHeight);
1196end;
1197
1198procedure TBGLCanvas.EnableScissor(AValue: TRect);
1199begin
1200 glScissor(AValue.left,Height-AValue.bottom,AValue.right-AValue.left,AValue.Bottom-AValue.Top);
1201 glEnable(GL_SCISSOR_TEST);
1202end;
1203
1204procedure TBGLCanvas.DisableScissor;
1205begin
1206 glDisable(GL_SCISSOR_TEST);
1207end;
1208
1209function TBGLCanvas.GetBlendMode: TOpenGLBlendMode;
1210begin
1211 result := FBlendMode;
1212end;
1213
1214procedure TBGLCanvas.SetBlendMode(AValue: TOpenGLBlendMode);
1215begin
1216 FBlendMode := AValue;
1217end;
1218
1219procedure TBGLCanvas.SetActiveFrameBuffer(AValue: TBGLCustomFrameBuffer);
1220var
1221 m: TMatrix4D;
1222begin
1223 if AValue = ActiveFrameBuffer then exit;
1224 inherited SetActiveFrameBuffer(AValue);
1225 if AValue = nil then
1226 glBindFramebuffer(GL_FRAMEBUFFER, 0)
1227 else
1228 glBindFramebuffer(GL_FRAMEBUFFER, PGLuint(AValue.Handle)^);
1229
1230 glViewPort(0,0,Width,Height);
1231
1232 glMatrixMode(GL_PROJECTION);
1233 m := ProjectionMatrix;
1234 glLoadMatrixf(@m);
1235
1236 glMatrixMode(GL_MODELVIEW);
1237 m := AffineMatrixToMatrix4D(Matrix);
1238 glLoadMatrixf(@m);
1239end;
1240
1241destructor TBGLCanvas.Destroy;
1242begin
1243 FLighting.Free;
1244 inherited Destroy;
1245end;
1246
1247{ TBGLTexture }
1248
1249function TBGLTexture.GetOpenGLMaxTexSize: integer;
1250begin
1251 result := 0;
1252 glGetIntegerv( GL_MAX_TEXTURE_SIZE, @result );
1253end;
1254
1255function TBGLTexture.CreateOpenGLTexture(ARGBAData: PDWord;
1256 AAllocatedWidth, AAllocatedHeight, AActualWidth, AActualHeight: integer;
1257 RGBAOrder: boolean): TBGLTextureHandle;
1258var p: POpenGLTexture;
1259 providedFormat: GLenum;
1260begin
1261 if RGBAOrder then providedFormat:= GL_RGBA else providedFormat:= GL_BGRA;
1262 New(p);
1263 p^.AllocatedWidth := AAllocatedWidth;
1264 p^.AllocatedHeight := AAllocatedHeight;
1265 p^.ActualWidth := AActualWidth;
1266 p^.ActualHeight := AActualHeight;
1267
1268 glGenTextures( 1, @p^.ID );
1269 glBindTexture( GL_TEXTURE_2D, p^.ID );
1270 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1271 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1272 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, AAllocatedWidth, AAllocatedHeight, 0, providedFormat, GL_UNSIGNED_BYTE, ARGBAData );
1273 result := p;
1274end;
1275
1276procedure TBGLTexture.UpdateOpenGLTexture(ATexture: TBGLTextureHandle;
1277 ARGBAData: PDWord; AAllocatedWidth, AAllocatedHeight, AActualWidth,
1278 AActualHeight: integer; RGBAOrder: boolean);
1279var providedFormat: GLenum;
1280begin
1281 if RGBAOrder then providedFormat:= GL_RGBA else providedFormat:= GL_BGRA;
1282 SetOpenGLTextureSize(ATexture, AAllocatedWidth,AAllocatedHeight, AActualWidth,AActualHeight);
1283 glBindTexture( GL_TEXTURE_2D, TOpenGLTexture(ATexture^).ID );
1284 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, AAllocatedWidth, AAllocatedHeight, 0, providedFormat, GL_UNSIGNED_BYTE, ARGBAData );
1285end;
1286
1287class function TBGLTexture.SupportsBGRAOrder: boolean;
1288begin
1289 Result:= true;
1290end;
1291
1292procedure TBGLTexture.SetOpenGLTextureSize(ATexture: TBGLTextureHandle;
1293 AAllocatedWidth, AAllocatedHeight, AActualWidth, AActualHeight: integer);
1294begin
1295 with TOpenGLTexture(ATexture^) do
1296 begin
1297 ActualWidth := AActualWidth;
1298 ActualHeight:= AActualHeight;
1299 AllocatedWidth := AAllocatedWidth;
1300 AllocatedHeight := AAllocatedHeight;
1301 end;
1302end;
1303
1304procedure TBGLTexture.ComputeOpenGLFramesCoord(ATexture: TBGLTextureHandle;
1305 FramesX: Integer; FramesY: Integer);
1306var U,V: Single;
1307 tX, tY, fU, fV : Single;
1308 ix,iy,i: Integer;
1309begin
1310 with TOpenGLTexture(ATexture^) do
1311 begin
1312 if AllocatedWidth = 0 then
1313 U := 1
1314 else
1315 U := ActualWidth/AllocatedWidth;
1316 if AllocatedHeight = 0 then
1317 V := 1
1318 else
1319 V := ActualHeight/AllocatedHeight;
1320
1321 if FramesX < 1 then FramesX := 1;
1322 if FramesY < 1 then FramesY := 1;
1323
1324 SetLength( FramesCoord, FramesX * FramesY + 1 );
1325 fU := U / FramesX;
1326 fV := V / FramesY;
1327
1328 FramesCoord[ 0, 0 ].X := 0;
1329 FramesCoord[ 0, 0 ].Y := 0;
1330 FramesCoord[ 0, 1 ].X := U;
1331 FramesCoord[ 0, 1 ].Y := 0;
1332 FramesCoord[ 0, 2 ].X := U;
1333 FramesCoord[ 0, 2 ].Y := V;
1334 FramesCoord[ 0, 3 ].X := 0;
1335 FramesCoord[ 0, 3 ].Y := V;
1336
1337 ix := 1;
1338 iy := 1;
1339 for i := 1 to FramesX * FramesY do
1340 begin
1341 tX := ix * fU;
1342 tY := iy * fV;
1343
1344 FramesCoord[ i, 0 ].X := tX - fU;
1345 FramesCoord[ i, 0 ].Y := tY - fV;
1346
1347 FramesCoord[ i, 1 ].X := tX;
1348 FramesCoord[ i, 1 ].Y := tY - fV;
1349
1350 FramesCoord[ i, 2 ].X := tX;
1351 FramesCoord[ i, 2 ].Y := tY;
1352
1353 FramesCoord[ i, 3 ].X := tX - fU;
1354 FramesCoord[ i, 3 ].Y := tY;
1355
1356 inc(ix);
1357 if ix > FramesX then
1358 begin
1359 ix := 1;
1360 inc(iy);
1361 end;
1362 end;
1363
1364 end;
1365end;
1366
1367function TBGLTexture.GetOpenGLFrameCount(ATexture: TBGLTextureHandle): integer;
1368begin
1369 if ATexture = nil then
1370 result := 0
1371 else
1372 begin
1373 result := Length(TOpenGLTexture(ATexture^).FramesCoord);
1374 if result > 0 then dec(result); //first frame is whole picture
1375 end;
1376end;
1377
1378function TBGLTexture.GetEmptyTexture: TBGLTextureHandle;
1379begin
1380 result := nil;
1381end;
1382
1383procedure TBGLTexture.FreeOpenGLTexture(ATexture: TBGLTextureHandle);
1384begin
1385 glDeleteTextures( 1, @TOpenGLTexture(ATexture^).ID );
1386 Dispose(POpenGLTexture(ATexture));
1387end;
1388
1389procedure TBGLTexture.UpdateGLResampleFilter(ATexture: TBGLTextureHandle;
1390 AFilter: TOpenGLResampleFilter);
1391begin
1392 glBindTexture( GL_TEXTURE_2D, TOpenGLTexture(ATexture^).ID );
1393 if AFilter = orfLinear then
1394 begin
1395 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1396 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1397 end else
1398 begin
1399 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1400 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1401 end;
1402end;
1403
1404procedure TBGLTexture.InternalSetColor(const AColor: TBGRAPixel);
1405begin
1406 if TBGRAPixel_RGBAOrder then
1407 glColor4ubv(@AColor)
1408 else
1409 glColor4ub(AColor.red,AColor.green,AColor.blue,AColor.alpha);
1410end;
1411
1412procedure TBGLTexture.DoDrawTriangleOrQuad(const APoints: array of TPointF;
1413 const APointsZ: array of Single; const APoints3D: array of TPoint3D_128;
1414 const ANormals3D: array of TPoint3D_128; const ATexCoords: array of TPointF;
1415 const AColors: array of TColorF);
1416var
1417 i: Integer;
1418 factorX,factorY: single;
1419begin
1420 if (FOpenGLTexture = nil) or (Width = 0) or (Height = 0) then exit;
1421 with TOpenGLTexture(FOpenGLTexture^) do
1422 begin
1423 glEnable( GL_BLEND );
1424
1425 glEnable( GL_TEXTURE_2D );
1426 glBindTexture( GL_TEXTURE_2D, ID );
1427
1428 if FIsMask then
1429 begin
1430 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
1431 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE );
1432 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB );
1433 end else
1434 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1435
1436 ApplyBlendMode(BlendMode);
1437
1438 factorX := 1/Width;
1439 factorY := 1/Height;
1440
1441 if length(AColors) = 0 then
1442 glColor4f(1,1,1,1);
1443
1444 if length(APoints3D) <> 0 then
1445 begin
1446 if length(APoints3D) = 3 then
1447 glBegin( GL_TRIANGLES )
1448 else
1449 glBegin( GL_QUADS );
1450
1451 for i := 0 to high(APoints3D) do
1452 begin
1453 if length(AColors) <> 0 then glColor4fv( @AColors[i] );
1454 glTexCoord2f( (ATexCoords[i].x+0.5)*factorX, (ATexCoords[i].y+0.5)*factorY );
1455 if length(ANormals3D) <> 0 then glNormal3fv( @ANormals3D[i] );
1456 glVertex3fv( @APoints3D[i] );
1457 end;
1458 end else
1459 begin
1460 if length(APoints) = 3 then
1461 glBegin( GL_TRIANGLES )
1462 else
1463 glBegin( GL_QUADS );
1464
1465 if length(APointsZ) <> 0 then
1466 begin
1467 for i := 0 to high(APoints) do
1468 begin
1469 if length(AColors) <> 0 then glColor4fv( @AColors[i] );
1470 glTexCoord2f( (ATexCoords[i].x+0.5)*factorX, (ATexCoords[i].y+0.5)*factorY );
1471 if length(ANormals3D) <> 0 then glNormal3fv( @ANormals3D[i] );
1472 glVertex3f( APoints[i].x, APoints[i].y, APointsZ[i] );
1473 end;
1474 end else
1475 begin
1476 for i := 0 to high(APoints) do
1477 begin
1478 if length(AColors) <> 0 then glColor4fv( @AColors[i] );
1479 glTexCoord2f( (ATexCoords[i].x+0.5)*factorX, (ATexCoords[i].y+0.5)*factorY );
1480 if length(ANormals3D) <> 0 then glNormal3fv( @ANormals3D[i] );
1481 glVertex2fv( @APoints[i] );
1482 end;
1483 end;
1484 end;
1485
1486 glEnd;
1487 glDisable( GL_TEXTURE_2D );
1488 glDisable( GL_BLEND );
1489 end;
1490end;
1491
1492procedure TBGLTexture.DoDraw(pt1, pt2, pt3, pt4: TPointF; AColor: TBGRAPixel);
1493type
1494 TTexCoordIndex = array[0..3] of integer;
1495const
1496 FLIP_TEXCOORD : array[ 0..3 ] of TTexCoordIndex = ( ( 0, 1, 2, 3 ), ( 1, 0, 3, 2 ), ( 3, 2, 1, 0 ), ( 2, 3, 0, 1 ) );
1497var
1498 coordFlip: TTexCoordIndex;
1499begin
1500 if (FOpenGLTexture = nil) or (FFrame < 0) or (FFrame > FrameCount) then exit;
1501 with TOpenGLTexture(FOpenGLTexture^) do
1502 begin
1503 glEnable( GL_BLEND );
1504 glEnable( GL_TEXTURE_2D );
1505 glBindTexture( GL_TEXTURE_2D, ID );
1506
1507 if FIsMask then
1508 begin
1509 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
1510 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE );
1511 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB );
1512 end else
1513 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1514
1515 ApplyBlendMode(BlendMode);
1516
1517 coordFlip := FLIP_TEXCOORD[ Integer(FFlipX) + Integer(FFlipY)*2 ];
1518
1519 glBegin( GL_QUADS );
1520
1521 if GradientColors then
1522 InternalSetColor(FGradTopLeft)
1523 else
1524 InternalSetColor(AColor);
1525
1526 glTexCoord2fv( @FramesCoord[FFrame,coordFlip[0]] );
1527 glVertex2fv( @pt1 );
1528
1529 if GradientColors then
1530 InternalSetColor(FGradTopRight);
1531
1532 glTexCoord2fv( @FramesCoord[FFrame,coordFlip[1]] );
1533 glVertex2fv( @pt2 );
1534
1535 if GradientColors then
1536 InternalSetColor(FGradBottomRight);
1537
1538 glTexCoord2fv( @FramesCoord[FFrame,coordFlip[2]] );
1539 glVertex2fv( @pt3 );
1540
1541 if GradientColors then
1542 InternalSetColor(FGradBottomLeft);
1543
1544 glTexCoord2fv( @FramesCoord[FFrame,coordFlip[3]] );
1545 glVertex2fv( @pt4 );
1546
1547 glEnd;
1548 glDisable( GL_TEXTURE_2D );
1549 glDisable( GL_BLEND );
1550 end;
1551end;
1552
1553procedure TBGLTexture.DoStretchDraw(x, y, w, h: single; AColor: TBGRAPixel);
1554begin
1555 DoDraw(PointF(x, y), PointF(x+w, y), PointF(x+w, y+h), PointF(x, y+h), AColor);
1556end;
1557
1558procedure TBGLTexture.DoStretchDrawAngle(x, y, w, h, angleDeg: single;
1559 rotationCenter: TPointF; AColor: TBGRAPixel);
1560var
1561 m : TAffineMatrix;
1562begin
1563 m := AffineMatrixTranslation(rotationCenter.X,rotationCenter.Y)*
1564 AffineMatrixRotationDeg(angleDeg)*
1565 AffineMatrixTranslation(-rotationCenter.X,-rotationCenter.Y);
1566 DoDraw(m*PointF(x, y), m*PointF(x+w, y), m*PointF(x+w, y+h), m*PointF(x, y+h), AColor);
1567end;
1568
1569procedure TBGLTexture.DoDrawAffine(Origin, HAxis, VAxis: TPointF;
1570 AColor: TBGRAPixel);
1571begin
1572 DoDraw(Origin, HAxis, HAxis+(VAxis-Origin), VAxis, AColor);
1573end;
1574
1575procedure TBGLTexture.ToggleFlipX;
1576begin
1577 FFlipX := not FFlipX;
1578end;
1579
1580procedure TBGLTexture.ToggleFlipY;
1581begin
1582 FFlipY := not FFlipY;
1583end;
1584
1585procedure TBGLTexture.Bind(ATextureNumber: integer);
1586begin
1587 if (ATextureNumber < 0) or (ATextureNumber > 31) then
1588 raise exception.Create('Texture number out of bounds');
1589 if (glActiveTexture = nil) then
1590 begin
1591 if not Load_GL_version_1_3 then
1592 raise exception.Create('Cannot load OpenGL 1.3');
1593 end;
1594 glActiveTexture(GL_TEXTURE0 + ATextureNumber);
1595 glBindTexture(GL_TEXTURE_2D, POpenGLTexture(FOpenGLTexture)^.ID);
1596 if ATextureNumber<>0 then
1597 glActiveTexture(GL_TEXTURE0);
1598end;
1599
1600function TBGLTexture.FilterBlurMotion(ARadius: single; ABlurType: TRadialBlurType; ADirection: TPointF): IBGLTexture;
1601var shader: TBGLCustomShader;
1602 blurName: string;
1603begin
1604 blurName := 'TBGLBlurShader(' + RadialBlurTypeToStr[ABlurType] + ')';
1605 shader := BGLCanvas.Lighting.Shader[blurName];
1606 if shader = nil then
1607 begin
1608 shader := TBGLBlurShader.Create(BGLCanvas, ABlurType);
1609 BGLCanvas.Lighting.Shader[blurName] := shader;
1610 end;
1611 with (shader as TBGLBlurShader) do
1612 begin
1613 Radius := ARadius;
1614 Direction := ADirection;
1615 result := FilterBlurMotion(self);
1616 end;
1617end;
1618
1619function TBGLTexture.FilterBlurRadial(ARadius: single; ABlurType: TRadialBlurType): IBGLTexture;
1620var shader: TBGLCustomShader;
1621 blurName: String;
1622begin
1623 blurName := 'TBGLBlurShader(' + RadialBlurTypeToStr[ABlurType] + ')';
1624 shader := BGLCanvas.Lighting.Shader[blurName];
1625 if shader = nil then
1626 begin
1627 shader := TBGLBlurShader.Create(BGLCanvas, ABlurType);
1628 BGLCanvas.Lighting.Shader[blurName] := shader;
1629 end;
1630 with (shader as TBGLBlurShader) do
1631 begin
1632 Radius := ARadius;
1633 result := FilterBlurRadial(self);
1634 end;
1635end;
1636
1637procedure TBGLTexture.Init(ATexture: TBGLTextureHandle; AWidth,
1638 AHeight: integer; AOwned: boolean);
1639begin
1640 inherited Init(ATexture, AWidth, AHeight, AOwned);
1641 FFlipX := false;
1642 FFlipY := false;
1643 FBlendMode := obmNormal;
1644end;
1645
1646procedure TBGLTexture.NotifyInvalidFrameSize;
1647begin
1648 raise exception.Create('Invalid frame size');
1649end;
1650
1651procedure TBGLTexture.NotifyErrorLoadingFile(AFilenameUTF8: string);
1652begin
1653 raise exception.Create('Error loading file "'+AFilenameUTF8+'"');
1654end;
1655
1656function TBGLTexture.NewEmpty: TBGLCustomTexture;
1657begin
1658 result := TBGLTexture.Create;
1659end;
1660
1661function TBGLTexture.NewFromTexture(ATexture: TBGLTextureHandle; AWidth,
1662 AHeight: integer): TBGLCustomTexture;
1663begin
1664 result := TBGLTexture.Create(ATexture,AWidth,AHeight);
1665end;
1666
1667function TBGLTexture.Duplicate: TBGLCustomTexture;
1668begin
1669 Result:= inherited Duplicate;
1670 TBGLTexture(result).FFlipX := FFlipX;
1671 TBGLTexture(result).FFlipY := FFlipY;
1672end;
1673
1674{ TBGLBitmap }
1675
1676function TBGLBitmap.GetOpenGLMaxTexSize: integer;
1677begin
1678 result := 0;
1679 glGetIntegerv( GL_MAX_TEXTURE_SIZE, @result );
1680end;
1681
1682initialization
1683
1684 BGLBitmapFactory := TBGLBitmap;
1685 BGLTextureFactory := TBGLTexture;
1686 BGRASpriteGL.BGLSpriteEngine := TBGLDefaultSpriteEngine.Create;
1687 BGLCanvasInstance := TBGLCanvas.Create;
1688
1689finalization
1690
1691 BGLCanvasInstance.Free;
1692 BGLCanvasInstance := nil;
1693 BGRASpriteGL.BGLSpriteEngine.Free;
1694 BGRASpriteGL.BGLSpriteEngine := nil;
1695
1696end.
1697
Note: See TracBrowser for help on using the repository browser.