Skip to content

Commit 15a9a9e

Browse files
author
Erik van Bilsen
committed
Added 2.5 Light Casters tutorial
1 parent 29fa25f commit 15a9a9e

13 files changed

+1872
-3
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- BEGIN_INCLUDE(manifest) -->
3+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
4+
package="%package%"
5+
android:versionCode="%versionCode%"
6+
android:versionName="%versionName%"
7+
android:installLocation="%installLocation%">
8+
9+
<!-- This is the platform API where NativeActivity was introduced. -->
10+
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
11+
<%uses-permission%>
12+
<uses-feature android:glEsVersion="0x00020000" android:required="True"/>
13+
<application android:persistent="%persistent%"
14+
android:restoreAnyVersion="%restoreAnyVersion%"
15+
android:label="%label%"
16+
android:debuggable="%debuggable%"
17+
android:largeHeap="%largeHeap%"
18+
android:icon="%icon%"
19+
android:theme="%theme%"
20+
android:hardwareAccelerated="%hardwareAccelerated%">
21+
22+
<%application-meta-data%>
23+
<%services%>
24+
<!-- Our activity is a subclass of the built-in NativeActivity framework class.
25+
This will take care of integrating with our NDK code. -->
26+
<activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
27+
android:label="%activityLabel%"
28+
android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
29+
android:launchMode="singleTask">
30+
<!-- Tell NativeActivity the name of our .so -->
31+
<meta-data android:name="android.app.lib_name"
32+
android:value="%libNameValue%" />
33+
<intent-filter>
34+
<action android:name="android.intent.action.MAIN" />
35+
<category android:name="android.intent.category.LAUNCHER" />
36+
</intent-filter>
37+
</activity>
38+
<%activity%>
39+
<%receivers%>
40+
</application>
41+
</manifest>
42+
<!-- END_INCLUDE(manifest) -->
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
unit App;
2+
3+
{$INCLUDE 'Sample.inc'}
4+
5+
interface
6+
7+
uses
8+
System.Classes,
9+
System.UITypes,
10+
System.SysUtils,
11+
{$INCLUDE 'OpenGL.inc'}
12+
Sample.Classes,
13+
Sample.App;
14+
15+
type
16+
TLightCastersApp = class(TApplication)
17+
private
18+
FCamera: ICamera;
19+
FLightingShader: IShader;
20+
FContainerVAO: IVertexArray;
21+
FDiffuseMap: GLuint;
22+
FSpecularMap: GLuint;
23+
FUniformViewPos: GLint;
24+
FUniformLightPosition: GLint;
25+
FUniformLightDirection: GLint;
26+
FUniformLightCutOff: GLint;
27+
FUniformLightOuterCutOff: GLint;
28+
FUniformLightConstant: GLint;
29+
FUniformLightLinear: GLint;
30+
FUniformLightQuadratic: GLint;
31+
FUniformLightAmbient: GLint;
32+
FUniformLightDiffuse: GLint;
33+
FUniformLightSpecular: GLint;
34+
FUniformMaterialShininess: GLint;
35+
FUniformContainerModel: GLint;
36+
FUniformContainerView: GLint;
37+
FUniformContainerProjection: GLint;
38+
FUniformContainerNormalMatrix: GLint;
39+
public
40+
procedure Initialize; override;
41+
procedure Update(const ADeltaTimeSec, ATotalTimeSec: Double); override;
42+
procedure Shutdown; override;
43+
procedure Resize(const AWidth, AHeight: Integer); override;
44+
public
45+
procedure KeyDown(const AKey: Integer; const AShift: TShiftState); override;
46+
procedure KeyUp(const AKey: Integer; const AShift: TShiftState); override;
47+
procedure MouseDown(const AButton: TMouseButton; const AShift: TShiftState;
48+
const AX, AY: Single); override;
49+
procedure MouseMove(const AShift: TShiftState; const AX, AY: Single); override;
50+
procedure MouseUp(const AButton: TMouseButton; const AShift: TShiftState;
51+
const AX, AY: Single); override;
52+
procedure MouseWheel(const AShift: TShiftState; const AWheelDelta: Integer); override;
53+
end;
54+
55+
implementation
56+
57+
uses
58+
Neslib.Stb.Image,
59+
Neslib.FastMath;
60+
61+
const
62+
{ Each container vertex consists of a 3-element position and a 3-element
63+
normal and a 2-element texture coordinate.
64+
Each group of 4 vertices defines a side of a cube. }
65+
CONTAINER_VERTICES: array [0..191] of Single = (
66+
// Positions // Normals // Texture Coords
67+
-0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 0.0, 0.0,
68+
0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 0.0,
69+
0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 1.0,
70+
-0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 0.0, 1.0,
71+
72+
-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 0.0,
73+
0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 0.0,
74+
0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0,
75+
-0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 1.0,
76+
77+
-0.5, 0.5, 0.5, -1.0, 0.0, 0.0, 1.0, 0.0,
78+
-0.5, 0.5, -0.5, -1.0, 0.0, 0.0, 1.0, 1.0,
79+
-0.5, -0.5, -0.5, -1.0, 0.0, 0.0, 0.0, 1.0,
80+
-0.5, -0.5, 0.5, -1.0, 0.0, 0.0, 0.0, 0.0,
81+
82+
0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 0.0,
83+
0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 1.0,
84+
0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 0.0, 1.0,
85+
0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0.0,
86+
87+
-0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 0.0, 1.0,
88+
0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 1.0, 1.0,
89+
0.5, -0.5, 0.5, 0.0, -1.0, 0.0, 1.0, 0.0,
90+
-0.5, -0.5, 0.5, 0.0, -1.0, 0.0, 0.0, 0.0,
91+
92+
-0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 1.0,
93+
0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 1.0,
94+
0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 0.0,
95+
-0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 0.0);
96+
97+
const
98+
{ The indices define 2 triangles per cube face, 6 faces total }
99+
INDICES: array [0..35] of UInt16 = (
100+
0, 1, 2, 2, 3, 0,
101+
4, 5, 6, 6, 7, 4,
102+
8, 9, 10, 10, 11, 8,
103+
12, 13, 14, 14, 15, 12,
104+
16, 17, 18, 18, 19, 16,
105+
20, 21, 22, 22, 23, 20);
106+
107+
const
108+
// Positions all containers
109+
CUBE_POSITIONS: array [0..9] of TVector3 = (
110+
(X: 0.0; Y: 0.0; Z: 0.0),
111+
(X: 2.0; Y: 5.0; Z: -15.0),
112+
(X: -1.5; Y: -2.2; Z: -2.5),
113+
(X: -3.8; Y: -2.0; Z: -12.3),
114+
(X: 2.4; Y: -0.4; Z: -3.5),
115+
(X: -1.7; Y: 3.0; Z: -7.5),
116+
(X: 1.3; Y: -2.0; Z: -2.5),
117+
(X: 1.5; Y: 2.0; Z: -2.5),
118+
(X: 1.5; Y: 0.2; Z: -1.5),
119+
(X: -1.3; Y: 1.0; Z: -1.5));
120+
121+
{ TLightCastersApp }
122+
123+
procedure TLightCastersApp.Initialize;
124+
var
125+
VertexLayout: TVertexLayout;
126+
Data: TBytes;
127+
Image: Pointer;
128+
ImageWidth, ImageHeight, ImageComponents: Integer;
129+
begin
130+
{ Initialize the asset manager }
131+
TAssets.Initialize;
132+
133+
{ Enable depth testing }
134+
glEnable(GL_DEPTH_TEST);
135+
136+
{ Create camera }
137+
FCamera := TCamera.Create(Width, Height, Vector3(0, 0, 3));
138+
139+
{ Build and compile our shader programs }
140+
FLightingShader := TShader.Create('shaders/light_casters.vs', 'shaders/light_casters.fs');
141+
FUniformViewPos := FLightingShader.GetUniformLocation('viewPos');
142+
FUniformLightPosition := FLightingShader.GetUniformLocation('light.position');
143+
FUniformLightDirection := FLightingShader.GetUniformLocation('light.direction');
144+
FUniformLightCutOff := FLightingShader.GetUniformLocation('light.cutOff');
145+
FUniformLightOuterCutOff := FLightingShader.GetUniformLocation('light.outerCutOff');
146+
FUniformLightConstant := FLightingShader.GetUniformLocation('light.constant');
147+
FUniformLightLinear := FLightingShader.GetUniformLocation('light.linear');
148+
FUniformLightQuadratic := FLightingShader.GetUniformLocation('light.quadratic');
149+
FUniformLightAmbient := FLightingShader.GetUniformLocation('light.ambient');
150+
FUniformLightDiffuse := FLightingShader.GetUniformLocation('light.diffuse');
151+
FUniformLightSpecular := FLightingShader.GetUniformLocation('light.specular');
152+
FUniformMaterialShininess := FLightingShader.GetUniformLocation('material.shininess');
153+
FUniformContainerModel := FLightingShader.GetUniformLocation('model');
154+
FUniformContainerView := FLightingShader.GetUniformLocation('view');
155+
FUniformContainerProjection := FLightingShader.GetUniformLocation('projection');
156+
FUniformContainerNormalMatrix := FLightingShader.GetUniformLocation('normalMatrix');
157+
158+
{ Define layout of the attributes in the Lighting shader }
159+
VertexLayout.Start(FLightingShader)
160+
.Add('position', 3)
161+
.Add('normal', 3)
162+
.Add('texCoords', 2);
163+
164+
{ Create the vertex array for the container. }
165+
FContainerVAO := TVertexArray.Create(VertexLayout,
166+
CONTAINER_VERTICES, SizeOf(CONTAINER_VERTICES), INDICES);
167+
168+
{ Load textures }
169+
170+
{ Diffuse Map
171+
=========== }
172+
glGenTextures(1, @FDiffuseMap);
173+
glBindTexture(GL_TEXTURE_2D, FDiffuseMap);
174+
175+
{ Set our texture parameters }
176+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
177+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
178+
179+
{ Set texture filtering }
180+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
181+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
182+
183+
{ Load, create texture and generate mipmaps }
184+
Data := TAssets.Load('textures/container2.png');
185+
Assert(Assigned(Data));
186+
Image := stbi_load_from_memory(Data, Length(Data), ImageWidth, ImageHeight, ImageComponents, 3);
187+
Assert(Assigned(Image));
188+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ImageWidth, ImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, Image);
189+
stbi_image_free(Image);
190+
glBindTexture(GL_TEXTURE_2D, 0);
191+
glErrorCheck;
192+
193+
{ Specular Map
194+
============ }
195+
glGenTextures(1, @FSpecularMap);
196+
glBindTexture(GL_TEXTURE_2D, FSpecularMap);
197+
{ All upcoming GL_TEXTURE_2D operations now have effect on our texture object }
198+
199+
{ Set our texture parameters }
200+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
201+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
202+
203+
{ Set texture filtering }
204+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
205+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
206+
207+
{ Load, create texture and generate mipmaps }
208+
Data := TAssets.Load('textures/container2_specular.png');
209+
Assert(Assigned(Data));
210+
Image := stbi_load_from_memory(Data, Length(Data), ImageWidth, ImageHeight, ImageComponents, 3);
211+
Assert(Assigned(Image));
212+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ImageWidth, ImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, Image);
213+
stbi_image_free(Image);
214+
glBindTexture(GL_TEXTURE_2D, 0);
215+
glErrorCheck;
216+
217+
{ Set texture units }
218+
FLightingShader.Use;
219+
glUniform1i(FLightingShader.GetUniformLocation('material.diffuse'), 0);
220+
glUniform1i(FLightingShader.GetUniformLocation('material.specular'), 1);
221+
end;
222+
223+
procedure TLightCastersApp.KeyDown(const AKey: Integer; const AShift: TShiftState);
224+
begin
225+
if (AKey = vkEscape) then
226+
{ Terminate app when Esc key is pressed }
227+
Terminate
228+
else
229+
FCamera.ProcessKeyDown(AKey);
230+
end;
231+
232+
procedure TLightCastersApp.KeyUp(const AKey: Integer; const AShift: TShiftState);
233+
begin
234+
FCamera.ProcessKeyUp(AKey);
235+
end;
236+
237+
procedure TLightCastersApp.MouseDown(const AButton: TMouseButton;
238+
const AShift: TShiftState; const AX, AY: Single);
239+
begin
240+
FCamera.ProcessMouseDown(AX, AY);
241+
end;
242+
243+
procedure TLightCastersApp.MouseMove(const AShift: TShiftState; const AX, AY: Single);
244+
begin
245+
FCamera.ProcessMouseMove(AX, AY);
246+
end;
247+
248+
procedure TLightCastersApp.MouseUp(const AButton: TMouseButton;
249+
const AShift: TShiftState; const AX, AY: Single);
250+
begin
251+
FCamera.ProcessMouseUp;
252+
end;
253+
254+
procedure TLightCastersApp.MouseWheel(const AShift: TShiftState;
255+
const AWheelDelta: Integer);
256+
begin
257+
FCamera.ProcessMouseWheel(AWheelDelta);
258+
end;
259+
260+
procedure TLightCastersApp.Resize(const AWidth, AHeight: Integer);
261+
begin
262+
inherited;
263+
if Assigned(FCamera) then
264+
FCamera.ViewResized(AWidth, AHeight);
265+
end;
266+
267+
procedure TLightCastersApp.Shutdown;
268+
begin
269+
glDeleteTextures(1, @FDiffuseMap);
270+
glDeleteTextures(1, @FSpecularMap);
271+
end;
272+
273+
procedure TLightCastersApp.Update(const ADeltaTimeSec, ATotalTimeSec: Double);
274+
var
275+
Model, View, Projection, Translate, Rotate: TMatrix4;
276+
NormalMatrix: TMatrix3;
277+
I: Integer;
278+
begin
279+
FCamera.HandleInput(ADeltaTimeSec);
280+
281+
{ Define the viewport dimensions }
282+
glViewport(0, 0, Width, Height);
283+
284+
{ Clear the color and depth buffer }
285+
glClearColor(0.1, 0.1, 0.1, 1.0);
286+
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
287+
288+
{ Use corresponding shader when setting uniforms/drawing objects }
289+
FLightingShader.Use;
290+
glUniform3f(FUniformLightPosition, FCamera.Position.X, FCamera.Position.Y, FCamera.Position.Z);
291+
glUniform3f(FUniformLightDirection, FCamera.Front.X, FCamera.Front.Y, FCamera.Front.Z);
292+
glUniform1f(FUniformLightCutOff, Cos(Radians(12.5)));
293+
glUniform1f(FUniformLightOuterCutOff, Cos(Radians(17.5)));
294+
glUniform3f(FUniformViewPos, FCamera.Position.X, FCamera.Position.Y, FCamera.Position.Z);
295+
296+
{ Set light properties }
297+
glUniform3f(FUniformLightAmbient, 0.1, 0.1, 0.1);
298+
{ We set the diffuse intensity a bit higher; note that the right lighting
299+
conditions differ with each lighting method and environment.
300+
Each environment and lighting type requires some tweaking of these variables
301+
to get the best out of your environment. }
302+
glUniform3f(FUniformLightDiffuse, 0.8, 0.8, 0.8);
303+
glUniform3f(FUniformLightSpecular, 1.0, 1.0, 1.0);
304+
glUniform1f(FUniformLightConstant, 1.0);
305+
glUniform1f(FUniformLightLinear, 0.09);
306+
glUniform1f(FUniformLightQuadratic, 0.032);
307+
308+
{ Set material properties }
309+
glUniform1f(FUniformMaterialShininess, 32.0);
310+
311+
{ Create camera transformation }
312+
View := FCamera.GetViewMatrix;
313+
Projection.InitPerspectiveFovRH(Radians(FCamera.Zoom), Width / Height, 0.1, 100.0);
314+
315+
{ Pass matrices to shader }
316+
glUniformMatrix4fv(FUniformContainerView, 1, GL_FALSE, @View);
317+
glUniformMatrix4fv(FUniformContainerProjection, 1, GL_FALSE, @Projection);
318+
319+
{ Bind diffuse map }
320+
glActiveTexture(GL_TEXTURE0);
321+
glBindTexture(GL_TEXTURE_2D, FDiffuseMap);
322+
323+
{ Bind specular map }
324+
glActiveTexture(GL_TEXTURE1);
325+
glBindTexture(GL_TEXTURE_2D, FSpecularMap);
326+
327+
{ Draw 10 containers with the same VAO and VBO information;
328+
only their world space coordinates differ }
329+
FContainerVAO.BeginRender;
330+
for I := 0 to Length(CUBE_POSITIONS) - 1 do
331+
begin
332+
{ Create Model matrix }
333+
Translate.InitTranslation(CUBE_POSITIONS[I]);
334+
Rotate.InitRotation(Vector3(1.0, 0.3, 0.5), Radians(20.0 * I));
335+
Model := Rotate * Translate;
336+
337+
{ Calculate Normal matrix }
338+
NormalMatrix.Init(Model);
339+
NormalMatrix := NormalMatrix.Inverse.Transpose;
340+
341+
{ Draw the container }
342+
glUniformMatrix4fv(FUniformContainerModel, 1, GL_FALSE, @Model);
343+
glUniformMatrix3fv(FUniformContainerNormalMatrix, 1, GL_FALSE, @NormalMatrix);
344+
FContainerVAO.Render;
345+
end;
346+
FContainerVAO.EndRender;
347+
end;
348+
349+
end.

0 commit comments

Comments
 (0)