├── CubeMan3D ├── CubeMan3D.gif ├── readme.md └── src │ ├── CubeManFMX3D.dpr │ ├── CubeManFMX3D.dproj │ ├── CubeManFMX3D.res │ ├── Main.fmx │ └── Main.pas ├── GLPanel ├── Entitlement.TemplateOSX32.xml ├── Execute.CrossGL.pas ├── Execute.CubeMan.pas ├── Execute.FMX.GLPanels.Types.pas ├── Execute.FMX.GLPanels.Win.pas ├── Execute.FMX.GLPanels.pas ├── Execute.Presentation.Mac.pas ├── GLPanel.png ├── GLPanelDemo.dpr ├── GLPanelDemo.dproj ├── GLPanelDemo.res ├── GlPanelMac.png ├── Main.fmx ├── Main.pas └── readme.md ├── Isometric ├── Isometric.dpr ├── Isometric.dproj ├── Isometric.png ├── Isometric.res ├── Main.fmx ├── Main.pas └── readme.md ├── LICENSE ├── MoreThan8Lights ├── FMXLights.dpr ├── FMXLights.dproj ├── FMXLights.res ├── Main.fmx ├── Main.pas ├── readme.md ├── screen1.png ├── screen2.png └── screen3.png ├── PuzzleSolver ├── readme.md └── src │ ├── PuzzleSolver.Main.fmx │ ├── PuzzleSolver.Main.pas │ ├── PuzzleSolver.dpr │ ├── PuzzleSolver.dproj │ └── PuzzleSolver.res ├── README.md ├── SourceShaders ├── Execute.ShaderMaterial.pas ├── Form1.png ├── Main.fmx ├── Main.pas ├── ShaderSource.dpr ├── ShaderSource.dproj └── readme.md ├── TextPath ├── Execute.FMX.TextPath.fmx ├── Execute.FMX.TextPath.pas ├── Execute.FMX.TextPathDesigner.dpk ├── Execute.FMX.TextPathDesigner.dproj ├── Execute.FontBuilder.pas ├── TextPath.png ├── TextPath2.png └── readme.md └── WoodTexture ├── NathaanTFM.AS3Perlin.pas ├── Wood.FlashLike.pas ├── Wood.gif ├── WoodTexture.Main.fmx ├── WoodTexture.Main.pas ├── WoodTexture.dpr ├── WoodTexture.dproj ├── WoodTexture.res └── readme.md /CubeMan3D/CubeMan3D.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/CubeMan3D/CubeMan3D.gif -------------------------------------------------------------------------------- /CubeMan3D/readme.md: -------------------------------------------------------------------------------- 1 | # CubeMan3D for FMX 2 | 3 | Not a single line of code for this FMX demo :) 4 | 5 | ![screenshot](CubeMan3D.gif) -------------------------------------------------------------------------------- /CubeMan3D/src/CubeManFMX3D.dpr: -------------------------------------------------------------------------------- 1 | program CubeManFMX3D; 2 | 3 | uses 4 | // Removing those 2 units speedup a little the application starting process 5 | // System.StartUpCopy, 6 | // FMX.MobilePreview, 7 | FMX.Forms, 8 | Main in 'Main.pas' {Form1}; 9 | 10 | {$R *.res} 11 | 12 | begin 13 | Application.Initialize; 14 | Application.CreateForm(TForm1, Form1); 15 | Application.Run; 16 | end. 17 | -------------------------------------------------------------------------------- /CubeMan3D/src/CubeManFMX3D.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/CubeMan3D/src/CubeManFMX3D.res -------------------------------------------------------------------------------- /CubeMan3D/src/Main.fmx: -------------------------------------------------------------------------------- 1 | object Form1: TForm1 2 | Left = 0 3 | Top = 0 4 | Caption = 'Form1' 5 | Color = xFFFFFFFE 6 | ClientHeight = 653 7 | ClientWidth = 652 8 | FormFactor.Width = 320 9 | FormFactor.Height = 480 10 | FormFactor.Devices = [Desktop] 11 | DesignerMobile = True 12 | DesignerWidth = 652 13 | DesignerHeight = 653 14 | DesignerDeviceName = '' 15 | DesignerOrientation = 0 16 | DesignerOSVersion = '' 17 | object body: TRoundCube 18 | Position.X = 0.001703739166259766 19 | Position.Y = 25.150325775146480000 20 | Position.Z = 100.000000000000000000 21 | RotationAngle.Y = 30.000000000000000000 22 | Width = 15.000000000000000000 23 | Height = 17.000000000000000000 24 | Depth = 10.000000000000000000 25 | MaterialSource = LightMaterialSource1 26 | Quanternion = '(0,0.258819043636322,0,0.965925812721252)' 27 | object head: TRoundCube 28 | Position.Y = -15.000000000000000000 29 | Width = 10.000000000000000000 30 | Height = 10.000000000000000000 31 | Depth = 10.000000000000000000 32 | MaterialSource = LightMaterialSource1 33 | end 34 | object Shoulder2: TDummy 35 | Position.X = 7.500000000000000000 36 | Position.Y = -8.500000000000000000 37 | RotationAngle.Z = 315.000000000000000000 38 | Width = 1.000000000000000000 39 | Height = 1.000000000000000000 40 | Depth = 1.000000000000000000 41 | Quanternion = 42 | '(-4.92974940868862E-8,-4.31467590544798E-8,-0.382683396339417,0.' + 43 | '923879444599152)' 44 | object Arm2: TRoundCube 45 | Position.Y = 5.000000000000000000 46 | Width = 6.000000000000000000 47 | Height = 10.000000000000000000 48 | Depth = 6.000000000000000000 49 | MaterialSource = LightMaterialSource1 50 | object Elbow2: TDummy 51 | Position.Y = 5.000000000000000000 52 | Width = 1.000000000000000000 53 | Height = 1.000000000000000000 54 | Depth = 1.000000000000000000 55 | object Forearm2: TRoundCube 56 | Position.Y = 5.000000000000000000 57 | Width = 6.000000000000000000 58 | Height = 10.000000000000000000 59 | Depth = 6.000000000000000000 60 | MaterialSource = LightMaterialSource1 61 | end 62 | object Forearm2Animation: TFloatAnimation 63 | AutoReverse = True 64 | Enabled = True 65 | Duration = 0.500000000000000000 66 | Loop = True 67 | PropertyName = 'RotationAngle.X' 68 | StartValue = 0.000000000000000000 69 | StopValue = -90.000000000000000000 70 | end 71 | end 72 | end 73 | object Arm2Animation: TFloatAnimation 74 | AutoReverse = True 75 | Enabled = True 76 | Duration = 1.000000000000000000 77 | Loop = True 78 | PropertyName = 'RotationAngle.X' 79 | StartValue = -80.000000000000000000 80 | StopValue = 80.000000000000000000 81 | end 82 | end 83 | object Shoulder1: TDummy 84 | Position.X = -7.500000000000000000 85 | Position.Y = -8.500000000000000000 86 | RotationAngle.Z = 45.000000000000000000 87 | Width = 1.000000000000000000 88 | Height = 1.000000000000000000 89 | Depth = 1.000000000000000000 90 | Quanternion = '(0,0,0.382683455944061,0.923879504203796)' 91 | object Arm1: TRoundCube 92 | Position.Y = 5.000000000000000000 93 | Width = 6.000000000000000000 94 | Height = 10.000000000000000000 95 | Depth = 6.000000000000000000 96 | MaterialSource = LightMaterialSource1 97 | object Elbow1: TDummy 98 | Position.Y = 5.000000000000000000 99 | Width = 1.000000000000000000 100 | Height = 1.000000000000000000 101 | Depth = 1.000000000000000000 102 | object Forearm1: TRoundCube 103 | Position.Y = 5.000000000000000000 104 | Width = 6.000000000000000000 105 | Height = 10.000000000000000000 106 | Depth = 6.000000000000000000 107 | MaterialSource = LightMaterialSource1 108 | end 109 | object Forearm1Animation: TFloatAnimation 110 | AutoReverse = True 111 | Enabled = True 112 | Duration = 0.500000000000000000 113 | Loop = True 114 | PropertyName = 'RotationAngle.X' 115 | StartValue = 0.000000000000000000 116 | StopValue = -90.000000000000000000 117 | end 118 | end 119 | end 120 | object Arm1Animation: TFloatAnimation 121 | AutoReverse = True 122 | Enabled = True 123 | Duration = 1.000000000000000000 124 | Loop = True 125 | PropertyName = 'RotationAngle.X' 126 | StartValue = 80.000000000000000000 127 | StopValue = -80.000000000000000000 128 | end 129 | end 130 | object Pelvis1: TDummy 131 | Position.X = -5.000000000000000000 132 | Position.Y = 8.500000000000000000 133 | Width = 1.000000000000000000 134 | Height = 1.000000000000000000 135 | Depth = 1.000000000000000000 136 | object Thigh1: TRoundCube 137 | Position.Y = 5.000000000000000000 138 | Width = 6.000000000000000000 139 | Height = 10.000000000000000000 140 | Depth = 6.000000000000000000 141 | MaterialSource = LightMaterialSource1 142 | object Knee1: TDummy 143 | Position.Y = 5.000000000000000000 144 | Width = 1.000000000000000000 145 | Height = 1.000000000000000000 146 | Depth = 1.000000000000000000 147 | object Leg1: TRoundCube 148 | Position.Y = 5.000000000000000000 149 | Width = 6.000000000000000000 150 | Height = 10.000000000000000000 151 | Depth = 6.000000000000000000 152 | MaterialSource = LightMaterialSource1 153 | end 154 | object Leg1KeyAnimation: TFloatKeyAnimation 155 | Enabled = True 156 | Duration = 2.000000000000000000 157 | Keys = < 158 | item 159 | end 160 | item 161 | Key = 0.500000000000000000 162 | end 163 | item 164 | Key = 0.800000011920929000 165 | Value = 120.000000000000000000 166 | end 167 | item 168 | Key = 1.000000000000000000 169 | end> 170 | Loop = True 171 | PropertyName = 'RotationAngle.X' 172 | StartFromCurrent = False 173 | end 174 | end 175 | end 176 | object Thigh1Animation: TFloatAnimation 177 | AutoReverse = True 178 | Enabled = True 179 | Duration = 1.000000000000000000 180 | Loop = True 181 | PropertyName = 'RotationAngle.X' 182 | StartValue = -45.000000000000000000 183 | StopValue = 45.000000000000000000 184 | end 185 | end 186 | object Pelvis2: TDummy 187 | Position.X = 5.000000000000000000 188 | Position.Y = 8.500000000000000000 189 | Width = 1.000000000000000000 190 | Height = 1.000000000000000000 191 | Depth = 1.000000000000000000 192 | object Thigh2: TRoundCube 193 | Position.Y = 5.000000000000000000 194 | Width = 6.000000000000000000 195 | Height = 10.000000000000000000 196 | Depth = 6.000000000000000000 197 | MaterialSource = LightMaterialSource1 198 | object Knee2: TDummy 199 | Position.Y = 5.000000000000000000 200 | Width = 1.000000000000000000 201 | Height = 1.000000000000000000 202 | Depth = 1.000000000000000000 203 | object Leg2: TRoundCube 204 | Position.Y = 5.000000000000000000 205 | Width = 6.000000000000000000 206 | Height = 10.000000000000000000 207 | Depth = 6.000000000000000000 208 | MaterialSource = LightMaterialSource1 209 | end 210 | object Leg2KeyAnimation: TFloatKeyAnimation 211 | Enabled = True 212 | Duration = 2.000000000000000000 213 | Keys = < 214 | item 215 | end 216 | item 217 | Key = 0.300000011920929000 218 | Value = 120.000000000000000000 219 | end 220 | item 221 | Key = 0.500000000000000000 222 | end 223 | item 224 | Key = 1.000000000000000000 225 | end> 226 | Loop = True 227 | PropertyName = 'RotationAngle.X' 228 | StartFromCurrent = False 229 | end 230 | end 231 | end 232 | object Thigh2Animation: TFloatAnimation 233 | AutoReverse = True 234 | Enabled = True 235 | Duration = 1.000000000000000000 236 | Loop = True 237 | PropertyName = 'RotationAngle.X' 238 | StartValue = 60.000000000000000000 239 | StopValue = -60.000000000000000000 240 | end 241 | end 242 | object TurnAround: TFloatAnimation 243 | Enabled = True 244 | Duration = 15.000000000000000000 245 | Loop = True 246 | PropertyName = 'RotationAngle.Y' 247 | StartValue = 0.000000000000000000 248 | StopValue = 360.000000000000000000 249 | end 250 | end 251 | object Light1: TLight 252 | Color = claWhite 253 | LightType = Directional 254 | SpotCutOff = 180.000000000000000000 255 | Position.X = -7.463888168334961000 256 | Position.Y = 14.385499954223630000 257 | Position.Z = 10.000011444091800000 258 | RotationAngle.X = 6.787704467773438000 259 | RotationAngle.Y = 15.729310035705570000 260 | RotationAngle.Z = 359.635833740234400000 261 | Width = 1.000000000000000000 262 | Height = 1.000000000000000000 263 | Depth = 1.000000000000000000 264 | Quanternion = 265 | '(0.0582080632448196,0.136406436562538,-0.0112425368279219,0.9888' + 266 | '77713680267)' 267 | end 268 | object LightMaterialSource1: TLightMaterialSource 269 | Diffuse = xFF7F7FFF 270 | Ambient = xFF00007F 271 | Emissive = claNull 272 | Specular = xFF606060 273 | Shininess = 30 274 | Left = 184 275 | Top = 280 276 | end 277 | end 278 | -------------------------------------------------------------------------------- /CubeMan3D/src/Main.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/CubeMan3D/src/Main.pas -------------------------------------------------------------------------------- /GLPanel/Entitlement.TemplateOSX32.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | <%appSandboxKeys%> 6 | 7 | 8 | -------------------------------------------------------------------------------- /GLPanel/Execute.CrossGL.pas: -------------------------------------------------------------------------------- 1 | unit Execute.CrossGL; 2 | 3 | { 4 | Cross-platform OpenGL implementation for Delphi Tokyo 5 | 6 | (c)2017 Execute SARL 7 | 8 | http://www.execute.fr 9 | 10 | } 11 | 12 | interface 13 | 14 | uses 15 | System.SysUtils, 16 | System.Math 17 | 18 | {$IFDEF Android} 19 | ,Androidapi.Log 20 | ,Androidapi.AppGlue 21 | ,Androidapi.Looper 22 | ,Androidapi.Egl 23 | ,Androidapi.Gles 24 | ,Androidapi.NativeWindow 25 | {$ENDIF} 26 | 27 | {$IFDEF MSWINDOWS} 28 | ,Winapi.Windows 29 | ,Winapi.Messages 30 | ,Winapi.OpenGL 31 | {$ENDIF} 32 | 33 | {$IFDEF MACOS} 34 | ,Macapi.Mach 35 | ,Macapi.CocoaTypes 36 | // ,Execute.MacOS 37 | {$ENDIF}; 38 | 39 | const 40 | GL_NO_ERROR =$0000; 41 | 42 | GL_ZERO =$0000; 43 | GL_ONE =$0001; 44 | 45 | GL_POINTS =$0000; // Treats each vertex as a single point. Vertex n defines point n. N points are drawn. 46 | GL_LINES =$0001; // Treats each pair of vertexes as an independent line segment. Vertexes 2n - 1 and 2n define line n. N/2 lines are drawn. 47 | GL_LINE_LOOP =$0002; // Draws a connected group of line segments from the first vertex to the last, then back to the first. Vertexes n and n+1 define line n. The last line, however, is defined by vertexes N and 1. N lines are drawn. 48 | GL_LINE_STRIP =$0003; // Draws a connected group of line segments from the first vertex to the last. Vertexes n and n+1 define line n. N - 1 lines are drawn. 49 | GL_TRIANGLES =$0004; // Treats each triplet of vertexes as an independent triangle. Vertexes 3n - 2, 3n-1, and 3n define triangle n. N/3 triangles are drawn. 50 | GL_TRIANGLE_STRIP =$0005; // Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertexes. For odd n, vertexes n, n+1, and n+2 define triangle n. 51 | // For even n, vertexes n+1, n, and n+2 define triangle n. N - 2 triangles are drawn. 52 | GL_TRIANGLE_FAN =$0006; // Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertexes. Vertexes 1, n+1, and n+2 define triangle n. N - 2 triangles are drawn. 53 | GL_QUADS =$0007; // Treats each group of four vertexes as an independent quadrilateral. Vertexes 4n - 3, 4n - 2, 4n - 1, and 4n define quadrilateral n. N/4 quadrilaterals are drawn. 54 | GL_QUAD_STRIP =$0008; // Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair of vertexes presented after the first pair. Vertexes 2n - 1, 2n, 2n+2, and 2n+1 define quadrilateral n. N quadrilaterals are drawn. Note that the order in which vertexes are used to construct a quadrilateral from strip data is different from that used with independent data. 55 | GL_POLYGON =$0009; // Draws a single, convex polygon. Vertexes 1 through N define this polygon. 56 | 57 | GL_DEPTH_BUFFER_BIT =$0100; // Indicates the depth buffer. 58 | 59 | GL_ACCUM =$0100; 60 | GL_LOAD =$0101; 61 | GL_RETURN =$0102; 62 | GL_MULT =$0103; 63 | GL_ADD =$0104; 64 | 65 | GL_ACCUM_BUFFER_BIT =$0200; // Indicates the accumulation buffer. 66 | GL_NEVER =$0200; // Never passes. 67 | GL_LESS =$0201; // Passes if the incoming z value is less than the stored z value. 68 | GL_EQUAL =$0202; // Passes if the incoming z value is equal to the stored z value. 69 | GL_LEQUAL =$0203; // Passes if the incoming z value is less than or equal to the stored z value. 70 | GL_GREATER =$0204; // Passes if the incoming z value is greater than the stored z value. 71 | GL_NOTEQUAL =$0205; // Passes if the incoming z value is not equal to the stored z value. 72 | GL_GEQUAL =$0206; // Passes if the incoming z value is greater than or equal to the stored z value. 73 | GL_ALWAYS =$0207; // Always passes. 74 | 75 | GL_SRC_COLOR =$0300; 76 | GL_ONE_MINUS_SRC_COLOR =$0301; 77 | GL_SRC_ALPHA =$0302; 78 | GL_ONE_MINUS_SRC_ALPHA =$0303; 79 | GL_DST_ALPHA =$0304; 80 | GL_ONE_MINUS_DST_ALPHA =$0305; 81 | GL_DST_COLOR =$0306; 82 | GL_ONE_MINUS_DST_COLOR =$0307; 83 | GL_SRC_ALPHA_SATURATE =$0308; 84 | 85 | GL_STENCIL_BUFFER_BIT =$0400; // Indicates the stencil buffer. 86 | GL_FRONT =$0404; 87 | GL_BACK =$0405; 88 | GL_FRONT_AND_BACK =$0408; 89 | 90 | GL_INVALID_ENUM =$0500; // is generated if cap is not one of the values listed above. 91 | GL_INVALID_VALUE =$0501; 92 | GL_INVALID_OPERATION =$0502; // is generated if glEnable is called between a call to glBegin and the corresponding call to glEnd. 93 | GL_STACK_OVERFLOW =$0503; 94 | GL_STACK_UNDERFLOW =$0504; 95 | GL_OUT_OF_MEMORY =$0505; 96 | 97 | GL_EXP =$0800; 98 | GL_EXP2 =$0801; 99 | 100 | GL_CW =$0900; 101 | GL_CCW =$0901; 102 | 103 | GL_POINT_SMOOTH =$0B10; // If enabled, draw points with proper filtering. Otherwise, draw aliased points. See glPointSize. 104 | GL_LINE_SMOOTH =$0B20; // If enabled, draw lines with correct filtering. Otherwise, draw aliased lines. See glLineWidth. 105 | GL_LINE_STIPPLE =$0B24; // If enabled, use the current line stipple pattern when drawing lines. See glLineStipple. 106 | GL_POLYGON_SMOOTH =$0B41; // If enabled, draw polygons with proper filtering. Otherwise, draw aliased polygons. See glPolygonMode. 107 | GL_POLYGON_STIPPLE =$0B42; // If enabled, use the current polygon stipple pattern when rendering polygons. See glPolygonStipple. 108 | GL_CULL_FACE =$0B44; // If enabled, cull polygons based on their winding in window coordinates. See glCullFace. 109 | GL_LIGHTING =$0B50; // If enabled, use the current lighting parameters to compute the vertex color or index. Otherwise, simply associate the current color or index with each vertex. See glMaterial, glLightModel, and glLight. 110 | GL_LIGHT_MODEL_LOCAL_VIEWER =$0B51; 111 | GL_LIGHT_MODEL_TWO_SIDE =$0B52; 112 | GL_LIGHT_MODEL_AMBIENT =$0B53; 113 | GL_COLOR_MATERIAL =$0B57; // If enabled, have one or more material parameters track the current color. See glColorMaterial. 114 | GL_FOG =$0B60; // If enabled, blend a fog color into the posttexturing color. See glFog. 115 | GL_FOG_INDEX =$0B61; 116 | GL_FOG_DENSITY =$0B62; 117 | GL_FOG_START =$0B63; 118 | GL_FOG_END =$0B64; 119 | GL_FOG_MODE =$0B65; 120 | GL_FOG_COLOR =$0B66; 121 | GL_DEPTH_TEST =$0B71; // If enabled, do depth comparisons and update the depth buffer. See glDepthFunc and glDepthRange. 122 | GL_ACCUM_CLEAR_VALUE =$0B80; 123 | GL_STENCIL_TEST =$0B90; // If enabled, do stencil testing and update the stencil buffer. See glStencilFunc and glStencilOp. 124 | GL_NORMALIZE =$0BA1; // If enabled, normal vectors specified with glNormal are scaled to unit length after transformation. See glNormal. 125 | GL_VIEWPORT =$0BA2; 126 | GL_MODELVIEW_MATRIX =$0BA6; 127 | GL_PROJECTION_MATRIX =$0BA7; 128 | GL_ALPHA_TEST =$0BC0; // If enabled, do alpha testing. See glAlphaFunc. 129 | GL_DITHER =$0BD0; // If enabled, dither color components or indices before they are written to the color buffer. 130 | GL_BLEND_DST =$0BE0; 131 | GL_BLEND_SRC =$0BE1; 132 | GL_BLEND =$0BE2; // If enabled, blend the incoming RGBA color values with the values in the color buffers. See glBlendFunc. 133 | GL_LOGIC_OP =$0BF1; // If enabled, apply the currently selected logical operation to the incoming and color buffer indices. See glLogicOp. 134 | 135 | GL_SCISSOR_TEST =$0C11; // If enabled, discard fragments that are outside the scissor rectangle. See glScissor. 136 | GL_PERSPECTIVE_CORRECTION_HINT =$0C50; 137 | GL_POINT_SMOOTH_HINT =$0C51; 138 | GL_LINE_SMOOTH_HINT =$0C52; 139 | GL_POLYGON_SMOOTH_HINT =$0C53; 140 | GL_FOG_HINT =$0C54; 141 | GL_TEXTURE_GEN_S =$0C60; // If enabled, the s texture coordinate is computed using the texture generation function defined with glTexGen. Otherwise, the current s texture coordinate is used. 142 | GL_TEXTURE_GEN_T =$0C61; // If enabled, the t texture coordinate is computed using the texture generation function defined with glTexGen. Otherwise, the current t texture coordinate is used. 143 | GL_TEXTURE_GEN_Q =$0C63; // If enabled, the q texture coordinate is computed using the texture generation function defined with glTexGen. Otherwise, the current q texture coordinate is used. 144 | GL_TEXTURE_GEN_R =$0C62; // If enabled, the r texture coordinate is computed using the texture generation function defined with glTexGen. Otherwise, the current r texture coordinate is used. 145 | GL_UNPACK_SWAP_BYTES =$0CF0; 146 | GL_UNPACK_LSB_FIRST =$0CF1; 147 | GL_UNPACK_ROW_LENGTH =$0CF2; 148 | GL_UNPACK_SKIP_PIXELS =$0CF4; 149 | GL_UNPACK_SKIP_ROWS =$0CF3; 150 | GL_UNPACK_ALIGNMENT =$0CF5; 151 | 152 | GL_PACK_SWAP_BYTES =$0D00; 153 | GL_PACK_LSB_FIRST =$0D01; 154 | GL_PACK_ROW_LENGTH =$0D02; 155 | GL_PACK_SKIP_PIXELS =$0D04; 156 | GL_PACK_SKIP_ROWS =$0D03; 157 | GL_PACK_ALIGNMENT =$0D05; 158 | GL_AUTO_NORMAL =$0D80; // If enabled, compute surface normal vectors analytically when either GL_MAP2_VERTEX_3 or GL_MAP2_VERTEX_4 is used to generate vertexes. See glMap2. 159 | 160 | GL_TEXTURE_1D =$0DE0; // If enabled, one-dimensional texturing is performed (unless two-dimensional texturing is also enabled). See glTexImage1D. 161 | GL_TEXTURE_2D =$0DE1; // If enabled, two-dimensional texturing is performed. See glTexImage2D. 162 | 163 | GL_DONT_CARE =$1100; // The client doesn't have a preference. 164 | GL_FASTEST =$1101; // The most efficient option should be chosen. 165 | GL_NICEST =$1102; // The most correct, or highest quality, option should be chosen. 166 | 167 | GL_AMBIENT =$1200; 168 | GL_DIFFUSE =$1201; 169 | GL_SPECULAR =$1202; 170 | GL_POSITION =$1203; 171 | GL_SPOT_DIRECTION =$1204; 172 | GL_SPOT_EXPONENT =$1205; 173 | GL_SPOT_CUTOFF =$1206; 174 | GL_CONSTANT_ATTENUATION =$1207; 175 | GL_LINEAR_ATTENUATION =$1208; 176 | GL_QUADRATIC_ATTENUATION =$1209; 177 | 178 | GL_COMPILE =$1300; 179 | GL_COMPILE_AND_EXECUTE =$1301; 180 | 181 | GL_BYTE =$1400; 182 | GL_UNSIGNED_BYTE =$1401; 183 | GL_SHORT =$1402; 184 | GL_UNSIGNED_SHORT =$1403; 185 | GL_INT =$1404; 186 | GL_UNSIGNED_INT =$1405; 187 | GL_FLOAT =$1406; 188 | GL_2_BYTES =$1407; 189 | GL_3_BYTES =$1408; 190 | GL_4_BYTES =$1409; 191 | GL_DOUBLE =$140A; 192 | GL_DOUBLE_EXT =$140A; 193 | 194 | GL_INVERT =$150A; 195 | 196 | GL_EMISSION =$1600; 197 | GL_SHININESS =$1601; 198 | GL_AMBIENT_AND_DIFFUSE =$1602; 199 | 200 | GL_MODELVIEW =$1700; // Applies subsequent matrix operations to the modelview matrix stack. 201 | GL_PROJECTION =$1701; // Applies subsequent matrix operations to the projection matrix stack. 202 | GL_TEXTURE =$1702; // Applies subsequent matrix operations to the texture matrix stack. 203 | 204 | GL_COLOR_INDEX =$1900; 205 | GL_RED =$1903; 206 | GL_GREEN =$1904; 207 | GL_BLUE =$1905; 208 | GL_ALPHA =$1906; 209 | GL_RGB =$1907; 210 | GL_RGBA =$1908; 211 | GL_LUMINANCE =$1909; 212 | GL_LUMINANCE_ALPHA =$190A; 213 | 214 | GL_BITMAP =$1A00; 215 | 216 | GL_POINT =$1B00; 217 | GL_LINE =$1B01; 218 | GL_FILL =$1B02; 219 | 220 | GL_RENDER =$1C00; 221 | GL_FEEDBACK =$1C01; 222 | GL_SELECT =$1C02; 223 | 224 | GL_FLAT =$1D00; 225 | GL_SMOOTH =$1D01; 226 | 227 | GL_KEEP =$1E00; 228 | GL_REPLACE =$1E01; 229 | GL_INCR =$1E02; 230 | GL_DECR =$1E03; 231 | 232 | GL_VENDOR =$1F00; // Returns the company responsible for this GL implementation. This name does not change from release to release. 233 | GL_RENDERER =$1F01; // Returns the name of the renderer. This name is typically specific to a particular configuration of a hardware platform. It does not change from release to release. 234 | GL_VERSION =$1F02; // Returns a version or release number. 235 | GL_EXTENSIONS =$1F03; // Returns a space-separated list of supported extensions to GL. ); 236 | 237 | GL_MODULATE =$2100; 238 | GL_DECAL =$2101; 239 | 240 | GL_TEXTURE_ENV_MODE =$2200; 241 | GL_TEXTURE_ENV_COLOR =$2201; 242 | GL_TEXTURE_ENV =$2300; 243 | 244 | GL_NEAREST =$2600; 245 | GL_LINEAR =$2601; 246 | 247 | GL_NEAREST_MIPMAP_NEAREST =$2700; 248 | GL_LINEAR_MIPMAP_NEAREST =$2701; 249 | GL_NEAREST_MIPMAP_LINEAR =$2702; 250 | GL_LINEAR_MIPMAP_LINEAR =$2703; 251 | 252 | GL_TEXTURE_MAG_FILTER =$2800; 253 | GL_TEXTURE_MIN_FILTER =$2801; 254 | GL_TEXTURE_WRAP_S =$2802; 255 | GL_TEXTURE_WRAP_T =$2803; 256 | 257 | GL_CLAMP =$2900; 258 | GL_REPEAT =$2901; 259 | 260 | GL_COLOR_BUFFER_BIT =$4000; // Indicates the buffers currently enabled for color writing. 261 | GL_LIGHT0 =$4000; // If enabled, include light i in the evaluation of the lighting equation. See glLightModel and glLight. 262 | GL_LIGHT1 =$4001; 263 | GL_LIGHT2 =$4002; 264 | GL_LIGHT3 =$4003; 265 | GL_LIGHT4 =$4004; 266 | GL_LIGHT5 =$4005; 267 | GL_LIGHT6 =$4006; 268 | GL_LIGHT7 =$4007; 269 | 270 | GL_POLYGON_OFFSET_EXT =$8037; 271 | GL_POLYGON_OFFSET_FILL =$8037; 272 | 273 | GL_VERTEX_ARRAY =$8074; 274 | GL_NORMAL_ARRAY =$8075; 275 | GL_COLOR_ARRAY =$8076; 276 | GL_INDEX_ARRAY =$8077; 277 | GL_TEXTURE_COORD_ARRAY =$8078; 278 | GL_EDGE_FLAG_ARRAY =$8079; 279 | GL_VERTEX_ARRAY_SIZE =$807A; 280 | GL_VERTEX_ARRAY_TYPE =$807B; 281 | GL_VERTEX_ARRAY_STRIDE =$807C; 282 | GL_NORMAL_ARRAY_TYPE =$807E; 283 | GL_NORMAL_ARRAY_STRIDE =$807F; 284 | GL_COLOR_ARRAY_SIZE =$8081; 285 | GL_COLOR_ARRAY_TYPE =$8082; 286 | GL_COLOR_ARRAY_STRIDE =$8083; 287 | GL_INDEX_ARRAY_TYPE =$8085; 288 | GL_INDEX_ARRAY_STRIDE =$8086; 289 | GL_TEXTURE_COORD_ARRAY_SIZE =$8088; 290 | GL_TEXTURE_COORD_ARRAY_TYPE =$8089; 291 | GL_TEXTURE_COORD_ARRAY_STRIDE =$808A; 292 | GL_EDGE_FLAG_ARRAY_STRIDE =$808C; 293 | 294 | GL_BGR_EXT =$80E0; 295 | GL_BGRA_EXT =$80E1; 296 | 297 | {$IFDEF Android} 298 | const 299 | OpenGL = '/usr/lib/libGLESv1_CM.so'; 300 | Prefix = ''; 301 | {$DEFINE CDECL} 302 | {$ENDIF} 303 | 304 | {$IFDEF MSWINDOWS} 305 | const 306 | OpenGL = 'OpenGL32.DLL'; 307 | {$DEFINE STDCALL} 308 | {$ENDIF} 309 | 310 | {$IFDEF MACOS} 311 | const 312 | OpenGL = '/System/Library/Frameworks/OpenGL.framework/OpenGL'; 313 | Prefix = '_'; 314 | {$DEFINE CDECL} 315 | {$ENDIF} 316 | 317 | {$IFDEF CDECL} 318 | procedure glClear(mask: GLbitfield); cdecl; external OpenGL name Prefix + 'glClear'; 319 | procedure glClearColor(red, green, blue, alpha: GLclampf); cdecl; external OpenGL name Prefix + 'glClearColor'; 320 | procedure glDrawArrays(mode: GLenum; first: GLint; count: GLsizei); cdecl; external OpenGL name Prefix + 'glDrawArrays'; 321 | procedure glEnable(cap: GLenum); cdecl; external OpenGL name Prefix + 'glEnable'; 322 | procedure glEnableClientState(array_: GLenum); cdecl; external OpenGL name Prefix + 'glEnableClientState'; 323 | procedure glFlush; cdecl; external OpenGL name Prefix + 'glFlush'; 324 | procedure glHint(target, mode: GLenum); cdecl; external OpenGL name Prefix + 'glHint'; 325 | procedure glLightfv(light, pname: GLenum; params: PGLfloat); cdecl; external OpenGL name Prefix + 'glLightfv'; 326 | procedure glLoadIdentity; cdecl; external OpenGL name Prefix + 'glLoadIdentity'; 327 | procedure glMatrixMode (mode: GLenum); cdecl; external OpenGL name Prefix + 'glMatrixMode'; 328 | procedure glMultMatrixf (m: PGLfloat); cdecl; external OpenGL name Prefix + 'glMultMatrixf'; 329 | procedure glNormalPointer(type_: GLenum; stride: GLsizei; pointer: PGLvoid); cdecl; external OpenGL name Prefix + 'glNormalPointer'; 330 | procedure glPopMatrix; cdecl; external OpenGL name Prefix + 'glPopMatrix'; 331 | procedure glPushMatrix; cdecl; external OpenGL name Prefix + 'glPushMatrix'; 332 | procedure glRotatef(angle, x, y, z: GLfloat); cdecl; external OpenGL name Prefix + 'glRotatef'; 333 | procedure glShadeModel(mode: GLenum); cdecl; external OpenGL name Prefix + 'glShadeModel'; 334 | procedure glTranslatef(x, y, z: GLfloat); cdecl; external OpenGL name Prefix + 'glTranslatef'; 335 | procedure glVertexPointer(size: GLint; type_: GLenum; stride: GLsizei; pointer: PGLvoid); cdecl; external OpenGL name Prefix + 'glVertexPointer'; 336 | procedure glViewport (x,y: GLint; width, height: GLsizei); cdecl; external OpenGL name Prefix + 'glViewport'; 337 | {$ENDIF} 338 | 339 | {$IFDEF STDCALL} 340 | procedure glClear(mask: GLbitfield); stdcall; external OpenGL; 341 | procedure glClearColor(red, green, blue, alpha: GLclampf); stdcall; external OpenGL; 342 | procedure glDrawArrays(mode: GLenum; first: GLint; count: GLsizei); stdcall; external OpenGL; 343 | procedure glEnable(cap: GLenum); stdcall; external OpenGL; 344 | procedure glEnableClientState(array_: GLenum); stdcall; external OpenGL; 345 | procedure glFlush; stdcall; external OpenGL; 346 | procedure glHint(target, mode: GLenum); stdcall; external OpenGL; 347 | procedure glLightfv(light, pname: GLenum; params: PGLfloat); stdcall; external OpenGL; 348 | procedure glLoadIdentity; stdcall; external OpenGL; 349 | procedure glNormalPointer(type_: GLenum; stride: GLsizei; pointer: Pointer); stdcall; external OpenGL; 350 | procedure glMatrixMode (mode: GLenum); stdcall; external OpenGL; 351 | procedure glMultMatrixf (m: PGLfloat); stdcall; external OpenGL; 352 | procedure glPopMatrix; stdcall; external OpenGL; 353 | procedure glPushMatrix; stdcall; external OpenGL; 354 | procedure glRotatef(angle, x, y, z: GLfloat); stdcall; external OpenGL; 355 | procedure glShadeModel(mode: GLenum); stdcall; external OpenGL; 356 | procedure glTranslatef(x, y, z: GLfloat); stdcall; external OpenGL; 357 | procedure glVertexPointer(size: GLint; type_: GLenum; stride: GLsizei; pointer: Pointer); stdcall; external OpenGL; 358 | procedure glViewport (x,y: GLint; width, height: GLsizei); stdcall; external OpenGL; 359 | {$ENDIF} 360 | 361 | procedure Log(const Str: string); 362 | function GetTickCount: Cardinal; 363 | 364 | implementation 365 | 366 | {$IFDEF ANDROID} 367 | 368 | procedure Log(const Str: string); 369 | {$IFDEF DEBUG} 370 | var 371 | M: TMarshaller; 372 | begin 373 | // Oh dear ! give us back our AnsiString ! 374 | LOGI(M.AsAnsi(Str).ToPointer); 375 | end; 376 | {$ELSE} 377 | begin 378 | end; 379 | {$ENDIF} 380 | 381 | // GetTickCount from System.pas (not published) 382 | const 383 | CLOCK_MONOTONIC = 1; 384 | 385 | type 386 | timespec = record 387 | tv_sec: Longint; 388 | tv_nsec: Int32; 389 | end; 390 | Ptimespec = ^timespec; 391 | 392 | function clock_gettime(Clk: Integer; Tp: Ptimespec): Integer; cdecl; 393 | external '/system/lib/libc' name 'clock_gettime'; 394 | 395 | function GetTickCount: Cardinal; inline; 396 | var 397 | res: timespec; 398 | begin 399 | clock_gettime(CLOCK_MONOTONIC, @res); 400 | Result := (Int64(1000000000) * res.tv_sec + res.tv_nsec) div 1000000; 401 | end; 402 | {$ENDIF Android} 403 | 404 | {$IFDEF MSWINDOWS} 405 | 406 | function GetTickCount: Cardinal stdcall; external kernel32; 407 | 408 | procedure Log(const Str: string); 409 | begin 410 | {$IFDEF DEBUG} 411 | AllocConsole; 412 | WriteLn(Str); 413 | {$ENDIF DEBUG} 414 | end; 415 | {$ENDIF MSWINDOWS} 416 | 417 | {$IFDEF MACOS} 418 | 419 | procedure Log(const Str: string); 420 | begin 421 | {$IFDEF DEBUG} 422 | WriteLn(Str); 423 | {$ENDIF DEBUG} 424 | end; 425 | 426 | const 427 | LibcLib = '/usr/lib/libc.dylib'; 428 | 429 | type 430 | TTimebaseInfoData = record 431 | Numer: UInt32; 432 | Denom: UInt32; 433 | end; 434 | 435 | function MachAbsoluteTime: UInt64; cdecl; external LibcLib name '_mach_absolute_time'; 436 | function MachTimebaseInfo(var TimebaseInfoData: TTimebaseInfoData): Integer; cdecl; external LibcLib name '_mach_timebase_info'; 437 | 438 | function AbsoluteToNanoseconds(AbsoluteTime: UInt64): UInt64; 439 | var 440 | Info: TTimebaseInfoData; 441 | begin 442 | MachTimebaseInfo(Info); 443 | Result := AbsoluteTime * Info.Numer; 444 | Result := Result div Info.Denom; 445 | end; 446 | 447 | function GetTickCount: Cardinal; //inline; 448 | begin 449 | Result := AbsoluteToNanoseconds(MachAbsoluteTime) div 1000000; 450 | end; 451 | 452 | {$ENDIF MACOS} 453 | 454 | procedure gluPerspective(fovy, aspect, zNear, zFar: double); 455 | var 456 | m: array[0..3,0..3] of Single; 457 | sn, cs: Extended; 458 | cotangent, deltaZ: Double; 459 | radians: Double; 460 | begin 461 | if aspect = 0 then 462 | Exit; 463 | deltaZ := zFar - zNear; 464 | if deltaZ = 0 then 465 | Exit; 466 | radians := fovy * PI / 360; 467 | SinCos(radians, sn, cs); 468 | if sn = 0 then 469 | Exit; 470 | cotangent := cs / sn; 471 | FillChar(m, SizeOf(m), 0); 472 | m[0,0] := cotangent / aspect; 473 | m[1,1] := cotangent; 474 | m[2,2] := -(zFar + zNear) / deltaZ; 475 | m[2,3] := -1; 476 | m[3,2] := -2 * zNear * zFar / deltaZ; 477 | glMultMatrixf(@m); 478 | end; 479 | 480 | end. 481 | 482 | -------------------------------------------------------------------------------- /GLPanel/Execute.CubeMan.pas: -------------------------------------------------------------------------------- 1 | unit Execute.CubeMan; 2 | 3 | { 4 | Pure OpenGL 3D man (c)2017 Execute SARL 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Execute.CrossGL; 11 | 12 | procedure glSetupCubeMan(); 13 | procedure glDrawCubeMan(); 14 | 15 | implementation 16 | 17 | const 18 | Vertices: array[0..7, 0..2] of Single = ( 19 | (-1.0, -1.0, -1.0), // 0 20 | ( 1.0, -1.0, -1.0), // 1 21 | ( 1.0, 1.0, -1.0), // 2 22 | (-1.0, 1.0, -1.0), // 3 23 | (-1.0, -1.0, 1.0), // 4 24 | ( 1.0, -1.0, 1.0), // 5 25 | ( 1.0, 1.0, 1.0), // 6 26 | (-1.0, 1.0, 1.0) // 7 27 | ); 28 | 29 | Indices: array[0..11, 0..2] of Byte = ( 30 | (0, 5, 4), (0, 1, 5), 31 | (1, 6, 5), (1, 2, 6), 32 | (2, 7, 6), (2, 3, 7), 33 | (3, 4, 7), (3, 0, 4), 34 | (4, 6, 7), (4, 5, 6), 35 | (3, 1, 0), (3, 2, 1) 36 | ); 37 | 38 | Diffuse : array[0..3] of Single = (0.5, 0.5, 1.0, 1); 39 | Ambient : array[0..3] of Single = (0.0, 0.0, 0.5, 1); 40 | Position: array[0..3] of Single = (0.0, 0.0, 0.0, 1); 41 | 42 | CUBE_SIZE = 3 * 2 * 6; 43 | CUBE_0 = 0; 44 | CUBE_1 = CUBE_SIZE; 45 | CUBE_2 = 2 * CUBE_SIZE; 46 | 47 | type 48 | TVertex = record 49 | x, y, z: Single; 50 | end; 51 | 52 | TPoint = record 53 | Vertex: TVertex; 54 | Normal: TVertex; 55 | end; 56 | 57 | TFace = array[0..2] of TPoint; // triangles 58 | 59 | TCube = array[0..11] of TFace; // 12 triangles 60 | 61 | var 62 | Cubes: array[0..2] of TCube; 63 | 64 | procedure BuildCube(var Cube: TCube; Width, Height, Depth: Single); 65 | var 66 | Face : Integer; 67 | Vertex: Integer; 68 | Normal: TVertex; 69 | begin 70 | FillChar(Normal, SizeOf(Normal), 0); 71 | for Face := 0 to 11 do 72 | begin 73 | case Face of 74 | 0: 75 | begin 76 | Normal.y := -1; 77 | end; 78 | 2: 79 | begin 80 | Normal.y := 0; 81 | Normal.x := 1; 82 | end; 83 | 4: 84 | begin 85 | Normal.x := 0; 86 | Normal.y := 1; 87 | end; 88 | 6: 89 | begin 90 | Normal.y := 0; 91 | Normal.x := -1; 92 | end; 93 | 8: 94 | begin 95 | Normal.x := 0; 96 | Normal.z := 1; 97 | end; 98 | 10: 99 | begin 100 | Normal.z := -1; 101 | end; 102 | end; 103 | for Vertex := 0 to 2 do 104 | begin 105 | Cube[Face, Vertex].Vertex.x := Vertices[Indices[Face, Vertex], 0] * Width; 106 | Cube[Face, Vertex].Vertex.y := Vertices[Indices[Face, Vertex], 1] * Height; 107 | Cube[Face, Vertex].Vertex.z := Vertices[Indices[Face, Vertex], 2] * Depth; 108 | Cube[Face, Vertex].Normal := Normal; 109 | end; 110 | end; 111 | end; 112 | 113 | procedure Init(); 114 | begin 115 | BuildCube(Cubes[0], 10, 17, 15); 116 | BuildCube(Cubes[1], 10, 10, 10); 117 | BuildCube(Cubes[2], 6, 6, 10); 118 | end; 119 | 120 | procedure glSetupCubeMan(); 121 | begin 122 | glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); 123 | glEnable(GL_CULL_FACE); 124 | glEnable(GL_DEPTH_TEST); 125 | glShadeModel(GL_SMOOTH); 126 | 127 | glLightfv(GL_LIGHT0, GL_AMBIENT, @Ambient); 128 | glLightfv(GL_LIGHT0, GL_DIFFUSE, @Diffuse); 129 | glLightfv(GL_LIGHT0, GL_POSITION, @Position); 130 | glEnable(GL_LIGHT0); 131 | glEnable(GL_LIGHTING); 132 | 133 | glVertexPointer(3, GL_FLOAT, SizeOf(TPoint), @Cubes[0, 0, 0].Vertex); 134 | glNormalPointer(GL_FLOAT, SizeOf(TPoint), @Cubes[0, 0, 0].Normal); 135 | 136 | glEnableClientState(GL_VERTEX_ARRAY); 137 | glEnableClientState(GL_NORMAL_ARRAY); 138 | end; 139 | 140 | procedure glDrawCubeMan(); 141 | var 142 | Time : Cardinal; 143 | Timer: Cardinal; 144 | begin 145 | Time := GetTickCount; 146 | 147 | glTranslatef(0, 0, -250); 148 | glRotatef(Time/50, 0, 1, 0); 149 | 150 | Timer := Time div 2; 151 | 152 | glPushMatrix; 153 | glDrawArrays(GL_TRIANGLES, CUBE_0, CUBE_SIZE); 154 | glTranslatef(0, +30, 0); 155 | glDrawArrays(GL_TRIANGLES, CUBE_1, CUBE_SIZE); 156 | glPopMatrix; 157 | glPushMatrix; 158 | glTranslatef(0, +15, 25-10); 159 | glRotatef(+45, 1, 0, 0); 160 | glRotatef(Abs((Timer div 3) mod 320 - 160) - 80, 0, 1, 0); 161 | glTranslatef(0, 0, 10); 162 | glDrawArrays(GL_TRIANGLES, CUBE_2, CUBE_SIZE); 163 | glTranslatef(0, 0, 20-10); 164 | glRotatef(Abs((Timer div 3) mod 180 - 90), 0, 1, 0); 165 | glTranslatef(0, 0, 10); 166 | glDrawArrays(GL_TRIANGLES, CUBE_2, CUBE_SIZE); 167 | glPopMatrix; 168 | glPushMatrix; 169 | glTranslatef(0, +15, 10-25); 170 | glRotatef(-45, 1, 0, 0); 171 | glRotatef(Abs((Timer div 3) mod 320 - 160) - 80, 0, 1, 0); 172 | glTranslatef(0, 0, -10); 173 | glDrawArrays(GL_TRIANGLES, CUBE_2, CUBE_SIZE); 174 | glTranslatef(0, 0, 10-20); 175 | glRotatef(-Abs((Timer div 3) mod 180 - 90), 0, 1, 0); 176 | glTranslatef(0, 0, -10); 177 | glDrawArrays(GL_TRIANGLES, CUBE_2, CUBE_SIZE); 178 | glPopMatrix; 179 | glPushMatrix; 180 | glTranslatef(0, 10-25, 10); 181 | glRotatef(-90, 1, 0, 0); 182 | glRotatef(Abs((Timer div 4) mod 240 - 120) - 60, 0, 1, 0); 183 | glTranslatef(0, 0, -10); 184 | glDrawArrays(GL_TRIANGLES, CUBE_2, CUBE_SIZE); 185 | glTranslatef(0, 0, 10-20); 186 | glRotatef((1-Integer((Timer div 2) mod 480) div 240) * (120 - Abs((Timer div 2) mod 240 - 120)), 0, 1, 0); 187 | glTranslatef(0, 0, -10); 188 | glDrawArrays(GL_TRIANGLES, CUBE_2, CUBE_SIZE); 189 | glPopMatrix; 190 | glPushMatrix; 191 | glTranslatef(0, 10-25, -10); 192 | glRotatef(-90, 1, 0, 0); 193 | glRotatef(-Abs((Timer div 4) mod 240 - 120) + 60, 0, 1, 0); 194 | glTranslatef(0, 0, -10); 195 | glDrawArrays(GL_TRIANGLES, CUBE_2, CUBE_SIZE); 196 | glTranslatef(0, 0, 10-20); 197 | glRotatef((Integer((Timer div 2) mod 480) div 240) * (120 - Abs((Timer div 2) mod 240 - 120)), 0, 1, 0); 198 | glTranslatef(0, 0, -10); 199 | glDrawArrays(GL_TRIANGLES, CUBE_2, CUBE_SIZE); 200 | glPopMatrix; 201 | end; 202 | 203 | initialization 204 | Init(); 205 | end. 206 | -------------------------------------------------------------------------------- /GLPanel/Execute.FMX.GLPanels.Types.pas: -------------------------------------------------------------------------------- 1 | unit Execute.FMX.GLPanels.Types; 2 | 3 | interface 4 | uses 5 | System.Classes, 6 | FMX.Controls.Presentation, 7 | FMX.Controls.Model; 8 | 9 | type 10 | TGLPanelModel = class(TDataModel) 11 | const 12 | STYLE_NAME = 'GLPanel-style'; 13 | PM_INVALIDE = PM_USER + 1; 14 | type 15 | TGLEvent = ( 16 | glSetup, 17 | glResize, 18 | glPaint 19 | ); 20 | private 21 | FEvents: array[TGLEvent] of TNotifyEvent; 22 | 23 | function getEvents(index : TGlevent) : TNotifyEvent; 24 | procedure setEvents(index : TGlevent; Value : TNotifyEvent); 25 | public 26 | function OnEvent(Event: TGLEvent): Boolean; 27 | property Events[index : TglEvent]: TNotifyEvent read getevents write setEvents; 28 | end; 29 | implementation 30 | 31 | 32 | function TGLPanelModel.OnEvent(Event: TGLEvent): Boolean; 33 | begin 34 | Result := Assigned(FEvents[Event]); 35 | if Result then 36 | FEvents[Event](Owner); 37 | end; 38 | 39 | function TGLPanelModel.getEvents(index: TGlevent): TNotifyEvent; 40 | begin 41 | Result := FEvents[index]; 42 | end; 43 | 44 | procedure TGLPanelModel.setEvents(index: TGlevent; Value: TNotifyEvent); 45 | begin 46 | FEvents[index] := Value; 47 | end; 48 | 49 | end. 50 | -------------------------------------------------------------------------------- /GLPanel/Execute.FMX.GLPanels.Win.pas: -------------------------------------------------------------------------------- 1 | unit Execute.FMX.GLPanels.Win; 2 | 3 | { 4 | FMX GLPanel for Delphi Tokyo (c)2017 Execute SARL 5 | } 6 | 7 | 8 | interface 9 | 10 | uses 11 | Winapi.Windows, 12 | Winapi.Messages, 13 | Winapi.OpenGL, 14 | Winapi.OpenGLExt, 15 | System.Classes, 16 | FMX.Controls, 17 | FMX.Controls.Model, 18 | FMX.Controls.Win, 19 | FMX.Presentation.Factory, 20 | FMX.Presentation.Win, 21 | Execute.FMX.GLPanels.Types; 22 | 23 | type 24 | TWinGLPanel = class(TWinPresentation) 25 | private 26 | // Windows stuffs 27 | FDC : HDC; 28 | FGL : HGLRC; 29 | FSetup: Boolean; 30 | procedure CreateGLContext; 31 | procedure DestroyGLContext; 32 | procedure ResizeGL; 33 | procedure WMEraseBkGnd(var Msg: TMessage); message WM_ERASEBKGND; 34 | procedure WMPaint(var Msg: TMessage); message WM_PAINT; 35 | // Presentation messages 36 | procedure PMInvalidate(var Msg: TDispatchMessage); message TGLPanelModel.PM_INVALIDE; 37 | private 38 | [unsafe] FModel: TGLPanelModel; 39 | protected 40 | // need this 41 | procedure CreateParams(var Params: TCreateParams); override; 42 | procedure CreateHandle; override; 43 | procedure DestroyHandle; override; 44 | procedure Resized; override; 45 | // link to the model 46 | function DefineModelClass: TDataModelClass; override; 47 | public 48 | constructor Create(AOwner: TComponent); override; 49 | end; 50 | 51 | implementation 52 | 53 | { TWinGLPanel } 54 | 55 | constructor TWinGLPanel.Create(AOwner: TComponent); 56 | begin 57 | inherited; 58 | FModel := TGLPanelModel(inherited Model); 59 | end; 60 | 61 | procedure TWinGLPanel.CreateGLContext; 62 | var 63 | pfd: TPIXELFORMATDESCRIPTOR; 64 | pixelformat: Integer; 65 | Cl: TRGBQuad; 66 | begin 67 | FDC := GetDC(Handle); 68 | if FDC = 0 then 69 | Exit; 70 | // set pixel format 71 | FillChar(pfd, SizeOf(pfd), 0); 72 | pfd.nSize := sizeof(pfd); 73 | pfd.nVersion := 1; 74 | pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; 75 | pfd.iLayerType := PFD_MAIN_PLANE; 76 | pfd.iPixelType := PFD_TYPE_RGBA; 77 | pfd.cColorBits := 32; 78 | pfd.iLayerType := PFD_MAIN_PLANE; 79 | pfd.cStencilBits:= 0; 80 | pixelformat := ChoosePixelFormat(FDC, @pfd); 81 | if PixelFormat = 0 then 82 | Exit; 83 | if not SetPixelFormat(FDC, pixelformat, @pfd) then 84 | Exit; 85 | // create OpenGL Context 86 | FGL := wglCreateContext(FDC); 87 | // select it 88 | wglMakeCurrent(FDC, FGL); 89 | // setup GL mode 90 | // setup the clear color 91 | // Integer(cl) := ColorToRGB(Color); 92 | // glClearColor(cl.rgbRed/255, cl.rgbGreen/255, cl.rgbBlue/255, 1); 93 | // setup the clear depth 94 | glClearDepth(1); 95 | 96 | InitOpenGLext; 97 | 98 | FSetup := FModel.OnEvent(TGLPanelModel.TGLEvent.glSetup); 99 | 100 | ResizeGL(); 101 | end; 102 | 103 | procedure TWinGLPanel.CreateHandle; 104 | begin 105 | inherited; 106 | if HandleAllocated then 107 | begin 108 | CreateGLContext; 109 | end; 110 | end; 111 | 112 | procedure TWinGLPanel.CreateParams(var Params: TCreateParams); 113 | begin 114 | inherited; 115 | Params.WindowClass.hbrBackground := GetStockObject(WHITE_BRUSH); 116 | end; 117 | 118 | function TWinGLPanel.DefineModelClass: TDataModelClass; 119 | begin 120 | Result := TGLPanelModel; 121 | end; 122 | 123 | procedure TWinGLPanel.DestroyGLContext; 124 | begin 125 | if FGL <> 0 then 126 | begin 127 | wglMakeCurrent(FDC, 0); 128 | wglDeleteContext(FGL); 129 | FGL := 0; 130 | end; 131 | if FDC <> 0 then 132 | begin 133 | DeleteDC(FDC); 134 | FDC := 0; 135 | end; 136 | end; 137 | 138 | procedure TWinGLPanel.DestroyHandle; 139 | begin 140 | if HandleAllocated then 141 | begin 142 | DestroyGLContext; 143 | end; 144 | inherited; 145 | end; 146 | 147 | procedure TWinGLPanel.PMInvalidate(var Msg: TDispatchMessage); 148 | begin 149 | InvalidateRect(Handle, nil, False); 150 | end; 151 | 152 | procedure TWinGLPanel.Resized; 153 | begin 154 | inherited; 155 | if FGL <> 0 then 156 | begin 157 | ResizeGL; 158 | InvalidateRect(Handle, nil, False); 159 | end; 160 | end; 161 | 162 | procedure TWinGLPanel.ResizeGL; 163 | var 164 | LSize: TSize; 165 | begin 166 | LSize := Size; 167 | glMatrixMode(GL_PROJECTION); 168 | glLoadIdentity; 169 | if LSize.cy <> 0 then 170 | gluPerspective(45, LSize.cx / LSize.cy, 1, 1000); 171 | glMatrixMode(GL_MODELVIEW); 172 | glLoadIdentity; 173 | glViewport(0, 0, LSize.cx, LSize.cy); 174 | FModel.OnEvent(TGLPanelModel.TGLEvent.glResize); 175 | end; 176 | 177 | procedure TWinGLPanel.WMEraseBkGnd(var Msg: TMessage); 178 | begin 179 | if FGL <> 0 then 180 | Msg.Result := 1 181 | else 182 | inherited; 183 | end; 184 | 185 | procedure TWinGLPanel.WMPaint(var Msg: TMessage); 186 | begin 187 | if FGL <> 0 then 188 | begin 189 | wglMakeCurrent(FDC, FGL); 190 | if FSetup = False then 191 | begin 192 | FModel.OnEvent(TGLPanelModel.TGLEvent.glSetup); 193 | FSetup := True; 194 | end; 195 | glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); 196 | glLoadIdentity(); 197 | FModel.OnEvent(TGLPanelModel.TGLEvent.glPaint); 198 | glFlush(); 199 | SwapBuffers(FDC); 200 | ValidateRect(Handle, nil); 201 | end else begin 202 | inherited; 203 | end; 204 | end; 205 | 206 | initialization 207 | TPresentationProxyFactory.Current.Register(TGLPanelModel.STYLE_NAME, TWinPresentationProxy); 208 | finalization 209 | TPresentationProxyFactory.Current.Unregister(TGLPanelModel.STYLE_NAME, TWinPresentationProxy); 210 | end. 211 | -------------------------------------------------------------------------------- /GLPanel/Execute.FMX.GLPanels.pas: -------------------------------------------------------------------------------- 1 | unit Execute.FMX.GLPanels; 2 | 3 | { 4 | FMX GLPanel for Delphi Tokyo (c)2017 Execute SARL 5 | } 6 | 7 | interface 8 | 9 | // http://yaroslavbrovin.ru/new-approach-of-development-of-firemonkey-control-control-model-presentation-part-1-en/ 10 | 11 | uses 12 | System.Classes, 13 | FMX.Types, 14 | FMX.Presentation.Messages, 15 | FMX.Controls.Model, 16 | Execute.FMX.GLPanels.Types, 17 | FMX.Controls.Presentation; 18 | 19 | type 20 | // the published GLPanel component 21 | TGLPanel = class(TPresentedControl) 22 | private 23 | // could be a [weak] reference, [unsafe] is fine also, but the value of FModel could be invalide 24 | [unsafe] FModel: TGLPanelModel; 25 | // generic event getter/setter 26 | function GetGLEvent(Index: TGLPanelModel.TGLEvent): TNotifyEvent; 27 | procedure SetGLEvent(Index: TGLPanelModel.TGLEvent; Value: TNotifyEvent); 28 | protected 29 | // explicit link to model class 30 | function DefineModelClass: TDataModelClass; override; 31 | // link to presentation (by name) 32 | function DefinePresentationName: string; override; 33 | 34 | public 35 | constructor Create(AOwner: TComponent); override; 36 | // refresh the OpenGL panel 37 | procedure Invalidate; 38 | published 39 | // change the general OpenGL settings 40 | property OnGLSetup: TNotifyEvent index TGLPanelModel.TGLEvent.glSetup read GetGLEvent write SetGLEvent; 41 | // when the Panel is resized 42 | property OnGLResize: TNotifyEvent index TGLPanelModel.TGLEvent.glResize read GetGLEvent write SetGLEvent; 43 | // when the Panel is rendering 44 | property OnGLPaint: TNotifyEvent index TGLPanelModel.TGLEvent.glPaint read GetGLEvent write SetGLEvent; 45 | end; 46 | 47 | implementation 48 | 49 | {$IFDEF MSWINDOWS} 50 | uses 51 | // Windows presentation for TGLPanel 52 | Execute.FMX.GLPanels.Win; 53 | 54 | {$ENDIF} 55 | 56 | {$IFDEF MACOS} 57 | uses 58 | Execute.Presentation.Mac; 59 | {$ENDIF} 60 | 61 | { TGLPanel } 62 | 63 | constructor TGLPanel.Create(AOwner: TComponent); 64 | begin 65 | inherited; 66 | FModel := GetModel; 67 | SetAcceptsControls(False); 68 | CanFocus := True; 69 | ClipChildren := False; 70 | end; 71 | 72 | function TGLPanel.DefineModelClass: TDataModelClass; 73 | begin 74 | Result := TGLPanelModel; 75 | end; 76 | 77 | function TGLPanel.DefinePresentationName: string; 78 | begin 79 | Result := TGLPanelModel.STYLE_NAME; 80 | end; 81 | 82 | function TGLPanel.GetGLEvent(Index: TGLPanelModel.TGLEvent): TNotifyEvent; 83 | begin 84 | Result := FModel.Events[Index]; 85 | end; 86 | 87 | procedure TGLPanel.SetGLEvent(Index: TGLPanelModel.TGLEvent; Value: TNotifyEvent); 88 | begin 89 | FModel.Events[Index] := Value; 90 | end; 91 | 92 | procedure TGLPanel.Invalidate; 93 | begin 94 | PresentationProxy.SendMessage(TGLPanelModel.PM_INVALIDE); 95 | end; 96 | 97 | 98 | end. 99 | -------------------------------------------------------------------------------- /GLPanel/Execute.Presentation.Mac.pas: -------------------------------------------------------------------------------- 1 | { ******************************************************* } 2 | { } 3 | { Delphi FireMonkey Platform } 4 | { } 5 | { Copyright(c) 2016 Embarcadero Technologies, Inc. } 6 | { All rights reserved } 7 | { } 8 | { ******************************************************* } 9 | 10 | unit Execute.Presentation.Mac; 11 | 12 | interface 13 | 14 | {$SCOPEDENUMS ON} 15 | 16 | uses 17 | System.TypInfo, 18 | System.Types, 19 | System.Classes, 20 | Macapi.ObjectiveC, 21 | Macapi.Foundation, 22 | Macapi.CocoaTypes, 23 | Macapi.AppKit, 24 | Macapi.CoreGraphics, 25 | FMX.Graphics, 26 | FMX.Controls.Presentation, 27 | FMX.Controls, 28 | FMX.Presentation.Messages, 29 | FMX.Forms, 30 | FMX.Types, 31 | Execute.FMX.GLPanels.Types, 32 | FMX.Controls.Model; 33 | 34 | type 35 | 36 | { TMacNativeView } 37 | 38 | TMacNativeView = class; 39 | 40 | IFMXNsView = interface(NsOpenglView) 41 | ['{BA60202C-47E6-4FD2-9999-30EC62C6384C}'] 42 | procedure drawRect(dirtyRect: NSRect); cdecl; 43 | end; 44 | 45 | TMacNativeView = class(TOCLocal) 46 | private 47 | private 48 | [Weak] 49 | FParentView: NSView; 50 | [Weak] 51 | FControl: TControl; 52 | [Weak] 53 | FModel: TGLPanelModel; 54 | [Weak] 55 | FForm: TCommonCustomForm; 56 | FSize: TSizeF; 57 | FVisible: Boolean; 58 | FControlSize: TSizeF; 59 | 60 | FContext: NSOpenGLContext; 61 | FPixelFormat: NSOpenGLPixelFormat; 62 | FContentRect: NSRect; 63 | 64 | procedure RefreshNativeParent; virtual; 65 | procedure SetupOpenGLContext; 66 | procedure UpdateOrderAndBounds; 67 | procedure ResizeGL; 68 | 69 | protected 70 | procedure InitView; virtual; 71 | function GetViewFrame: NSRect; 72 | procedure SetSize(const ASize: TSizeF); virtual; 73 | function GetObjectiveCClass: PTypeInfo; override; 74 | 75 | function GetView: NsOpenglView; overload; 76 | 77 | function GetParentView: NSView; 78 | procedure Resized; virtual; 79 | { Messages from PresentationProxy } 80 | procedure PMGetNativeObject(var AMessage: TDispatchMessageWithValue); message PM_GET_NATIVE_OBJECT; 81 | procedure PMRootChanged(var AMessage: TDispatchMessageWithValue); message PM_ROOT_CHANGED; 82 | procedure PMAncesstorPresentationLoaded(var AMessage: TDispatchMessageWithValue); message PM_ANCESTOR_PRESENTATION_LOADED; 83 | procedure PMRefreshParent(var AMessage: TDispatchMessage); message PM_REFRESH_PARENT; 84 | procedure PMChangeOrder(var AMessage: TDispatchMessage); message PM_CHANGE_ORDER; 85 | procedure PMAbsoluteChanged(var AMessage: TDispatchMessage); message PM_ABSOLUTE_CHANGED; 86 | procedure PMSetSize(var AMessage: TDispatchMessageWithValue); message PM_SET_SIZE; 87 | procedure PMGetSize(var AMessage: TDispatchMessageWithValue); message PM_GET_SIZE; 88 | procedure PMSetVisible(var AMessage: TDispatchMessageWithValue); message PM_SET_VISIBLE; 89 | procedure PMGetVisible(var AMessage: TDispatchMessageWithValue); message PM_GET_VISIBLE; 90 | procedure PMAncesstorVisibleChanged(var AMessage: TDispatchMessageWithValue); message PM_ANCESSTOR_VISIBLE_CHANGED; 91 | procedure PMSetAbsoluteEnabled(var AMessage: TDispatchMessageWithValue); message PM_SET_ABSOLUTE_ENABLED; 92 | procedure PMGetAbsoluteEnabled(var AMessage: TDispatchMessageWithValue); message PM_GET_ABSOLUTE_ENABLED; 93 | procedure PMDoExit(var AMessage: TDispatchMessage); message PM_DO_EXIT; 94 | procedure PMDoEnter(var AMessage: TDispatchMessage); message PM_DO_ENTER; 95 | procedure PMResetFocus(var AMessage: TDispatchMessage); message PM_RESET_FOCUS; 96 | 97 | procedure PMInvalidate(var AMessage: TDispatchMessage); message TGLPanelModel.PM_INVALIDE; 98 | 99 | 100 | 101 | public 102 | procedure drawRect(dirtyRect: NSRect); cdecl; 103 | property Control: TControl read FControl; 104 | 105 | function DefineModelClass: TDataModelClass; virtual; 106 | constructor Create; overload; virtual; 107 | constructor Create(const AModel: TDataModel; const AControl: TControl); overload; virtual; 108 | destructor Destroy; override; 109 | function HasControl: Boolean; 110 | procedure SetFocus; virtual; 111 | property Model: TGLPanelModel read FModel; 112 | property View: NsOpenglView read GetView; 113 | 114 | end; 115 | 116 | TMacNativeViewClass = class of TMacNativeView; 117 | 118 | /// Generics proxy for all Mac native presentations 119 | TMacPresentationProxy = class(TPresentationProxy) 120 | protected 121 | function CreateReceiver: TObject; override; 122 | end; 123 | 124 | implementation 125 | 126 | uses 127 | System.UITypes, 128 | System.SysUtils, 129 | System.Math, 130 | Macapi.Helpers, 131 | Macapi.ObjCRuntime, 132 | Macapi.OpenGL, 133 | FMX.Platform.Mac, 134 | FMX.Surfaces, 135 | FMX.Presentation.Factory, 136 | FMX.Helpers.Mac, 137 | FMX.Consts; 138 | 139 | constructor TMacNativeView.Create; 140 | begin 141 | inherited; 142 | FVisible := True; 143 | end; 144 | 145 | procedure TMacNativeView.InitView; 146 | var 147 | V: Pointer; 148 | 149 | begin 150 | V := NsOpenglView(Super).initWithFrame(GetViewFrame, TNSOpenGLView.OCClass.defaultPixelFormat); 151 | if NSAppKitVersionNumber >= NSAppKitVersionNumber10_7 then 152 | NsOpenglView(Super).setWantsBestResolutionOpenGLSurface(True); 153 | if GetObjectID <> V then 154 | UpdateObjectID(V); 155 | if HasControl then 156 | begin 157 | FParentView := GetParentView; 158 | if FParentView <> nil then 159 | FParentView.addSubview(NSView(Super)); 160 | end; 161 | end; 162 | 163 | constructor TMacNativeView.Create(const AModel: TDataModel; const AControl: TControl); 164 | begin 165 | FControl := AControl; 166 | FModel := AModel as TGLPanelModel; 167 | if FModel is DefineModelClass then 168 | FModel.Receiver := Self 169 | else 170 | raise EPresentationWrongModel.CreateFmt(SWrongModelClassType, [DefineModelClass.ClassName, FModel.ClassName]); 171 | 172 | Create; 173 | InitView; 174 | end; 175 | 176 | function TMacNativeView.DefineModelClass: TDataModelClass; 177 | begin 178 | Result := TDataModel; 179 | end; 180 | 181 | destructor TMacNativeView.Destroy; 182 | begin 183 | View.removeFromSuperview; 184 | inherited; 185 | end; 186 | 187 | function TMacNativeView.GetObjectiveCClass: PTypeInfo; 188 | begin 189 | Result := TypeInfo(IFMXNsView); 190 | end; 191 | 192 | function TMacNativeView.GetView: NsOpenglView; 193 | begin 194 | Result := NsOpenglView(Super); 195 | end; 196 | 197 | procedure TMacNativeView.SetupOpenGLContext; 198 | var 199 | Attributes: TArray; 200 | begin 201 | Attributes := TArray.Create(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy, NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, 16); 202 | Attributes := Attributes + [0]; 203 | FPixelFormat := TNSOpenGLPixelFormat.Wrap(TNSOpenGLPixelFormat.Alloc.initWithAttributes(@Attributes[0])); 204 | FContext := TNSOpenGLContext.Wrap(TNSOpenGLContext.Alloc.initWithFormat(FPixelFormat, nil)); 205 | View.setOpenGLContext(FContext); 206 | FContext.makeCurrentContext; 207 | ResizeGL(); 208 | end; 209 | 210 | function TMacNativeView.GetViewFrame: NSRect; 211 | begin 212 | if HasControl then 213 | Result := Nsrect.Create(FControl.AbsoluteRect) 214 | else 215 | Result := CGRectMake(0, 0, 50, 50); 216 | end; 217 | 218 | function TMacNativeView.HasControl: Boolean; 219 | begin 220 | Result := FControl <> nil; 221 | end; 222 | 223 | 224 | procedure TMacNativeView.SetFocus; 225 | begin 226 | View.becomeFirstResponder; 227 | end; 228 | 229 | procedure TMacNativeView.SetSize(const ASize: TSizeF); 230 | var 231 | ViewSize: NSSize; 232 | begin 233 | FSize := ASize; 234 | View.setFrameSize(cgsize.Create(FSize)); 235 | UpdateOrderAndBounds; 236 | end; 237 | 238 | 239 | function TMacPresentationProxy.CreateReceiver: TObject; 240 | var 241 | PresentationClass: TMacNativeViewClass; 242 | begin 243 | PresentationClass := T; 244 | Result := PresentationClass.Create(Model, PresentedControl); 245 | end; 246 | 247 | procedure TMacNativeView.PMRootChanged(var AMessage: TDispatchMessageWithValue); 248 | begin 249 | if AMessage.Value is TCommonCustomForm then 250 | FForm := TCommonCustomForm(AMessage.Value) 251 | else 252 | FForm := nil; 253 | RefreshNativeParent; 254 | end; 255 | 256 | procedure TMacNativeView.PMGetNativeObject(var AMessage: TDispatchMessageWithValue); 257 | begin 258 | AMessage.Value := View; 259 | end; 260 | 261 | procedure TMacNativeView.PMGetSize(var AMessage: TDispatchMessageWithValue); 262 | var 263 | Size: NSSize; 264 | begin 265 | AMessage.Value := FControlSize; 266 | end; 267 | 268 | function TMacNativeView.GetParentView: NSView; 269 | var 270 | FormHandle: TMacWindowHandle; 271 | begin 272 | if FForm <> nil then 273 | begin 274 | FormHandle := WindowHandleToPlatform(FForm.Handle); 275 | Result := FormHandle.View; 276 | end 277 | else 278 | Result := nil; 279 | end; 280 | 281 | procedure TMacNativeView.RefreshNativeParent; 282 | begin 283 | FParentView := nil; 284 | if HasControl then 285 | begin 286 | FParentView := GetParentView; 287 | if FParentView = nil then 288 | begin 289 | View.removeFromSuperview 290 | end 291 | else 292 | begin 293 | FParentView.addSubview(View); 294 | SetupOpenGLContext; 295 | end; 296 | end; 297 | end; 298 | 299 | procedure TMacNativeView.drawRect(dirtyRect: NSRect); 300 | begin 301 | glClearColor(0, 0, 0, 1.0); 302 | glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT); 303 | glLoadIdentity(); 304 | FModel.Events[glSetup](Self); 305 | FModel.Events[glPaint](Self); 306 | FContext.flushBuffer; 307 | end; 308 | 309 | procedure TMacNativeView.PMAncesstorPresentationLoaded(var AMessage: TDispatchMessageWithValue); 310 | begin 311 | RefreshNativeParent; 312 | UpdateOrderAndBounds; 313 | end; 314 | 315 | procedure TMacNativeView.PMRefreshParent(var AMessage: TDispatchMessage); 316 | begin 317 | RefreshNativeParent; 318 | end; 319 | 320 | procedure TMacNativeView.PMChangeOrder(var AMessage: TDispatchMessage); 321 | begin 322 | UpdateOrderAndBounds; 323 | end; 324 | 325 | procedure TMacNativeView.PMAbsoluteChanged(var AMessage: TDispatchMessage); 326 | begin 327 | UpdateOrderAndBounds; 328 | end; 329 | 330 | procedure TMacNativeView.PMSetSize(var AMessage: TDispatchMessageWithValue); 331 | begin 332 | FControlSize := AMessage.Value; 333 | UpdateOrderAndBounds; 334 | Resized; 335 | end; 336 | 337 | procedure TMacNativeView.PMSetVisible(var AMessage: TDispatchMessageWithValue); 338 | begin 339 | View.setHidden(not AMessage.Value); 340 | end; 341 | 342 | procedure TMacNativeView.PMGetVisible(var AMessage: TDispatchMessageWithValue); 343 | begin 344 | AMessage.Value := not View.isHiddenOrHasHiddenAncestor; 345 | end; 346 | 347 | procedure TMacNativeView.PMAncesstorVisibleChanged(var AMessage: TDispatchMessageWithValue); 348 | var 349 | LMessage: TDispatchMessageWithValue; 350 | begin 351 | LMessage.Value := Control.Visible and Control.ParentedVisible; 352 | PMSetVisible(LMessage); 353 | if LMessage.Value then 354 | UpdateOrderAndBounds; 355 | end; 356 | 357 | procedure TMacNativeView.PMSetAbsoluteEnabled(var AMessage: TDispatchMessageWithValue); 358 | begin 359 | 360 | end; 361 | 362 | procedure TMacNativeView.PMGetAbsoluteEnabled(var AMessage: TDispatchMessageWithValue); 363 | begin 364 | AMessage.Value := not View.isHiddenOrHasHiddenAncestor; 365 | end; 366 | 367 | procedure TMacNativeView.PMDoExit(var AMessage: TDispatchMessage); 368 | begin 369 | end; 370 | 371 | procedure TMacNativeView.PMDoEnter(var AMessage: TDispatchMessage); 372 | begin 373 | end; 374 | 375 | procedure TMacNativeView.PMResetFocus(var AMessage: TDispatchMessage); 376 | begin 377 | end; 378 | 379 | procedure TMacNativeView.UpdateOrderAndBounds; 380 | var 381 | temp: NSRect; 382 | winrect : NSRect; 383 | begin 384 | temp := GetViewFrame; 385 | if GetParentView <> nil then 386 | begin 387 | winrect := GetParentView.frame; 388 | temp.origin.y := winrect.size.height - (temp.origin.y + temp.size.height); 389 | end; 390 | View.setFrame(temp); 391 | Resized; 392 | end; 393 | 394 | procedure TMacNativeView.Resized; 395 | begin 396 | ResizeGL; 397 | FModel.OnEvent(TGLPanelModel.TGLEvent.glResize); 398 | end; 399 | 400 | procedure TMacNativeView.PMInvalidate(var AMessage: TDispatchMessage); 401 | begin 402 | View.display; 403 | end; 404 | 405 | procedure TMacNativeView.ResizeGL; 406 | 407 | procedure perspective(const fovy, aspect, zNear, zFar: double); 408 | var 409 | xmin, xmax, ymin, ymax: double; 410 | begin 411 | ymax := zNear * tan(fovy * PI / 360.0); 412 | ymin := - ymax; 413 | xmin := ymin * aspect; 414 | xmax := ymax * aspect; 415 | glFrustum(xmin, xmax, ymin, ymax, zNear, zFar); 416 | end; 417 | 418 | var 419 | LSize: TSizeF; 420 | 421 | begin 422 | LSize := GetViewFrame.size.ToSizeF; 423 | glMatrixMode(GL_PROJECTION); 424 | glLoadIdentity; 425 | if LSize.cy <> 0 then 426 | perspective(45, LSize.cx / LSize.cy, 1, 1000); 427 | 428 | glMatrixMode(GL_MODELVIEW); 429 | glLoadIdentity; 430 | end; 431 | 432 | initialization 433 | 434 | InitOpenGL; 435 | TPresentationProxyFactory.Current.Register(TGLPanelModel.STYLE_NAME, TMacPresentationProxy); 436 | 437 | finalization 438 | 439 | TPresentationProxyFactory.Current.Unregister(TGLPanelModel.STYLE_NAME, TMacPresentationProxy); 440 | 441 | end. 442 | -------------------------------------------------------------------------------- /GLPanel/GLPanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/GLPanel/GLPanel.png -------------------------------------------------------------------------------- /GLPanel/GLPanelDemo.dpr: -------------------------------------------------------------------------------- 1 | program GLPanelDemo; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | Main in 'Main.pas' {Form2}, 7 | Execute.FMX.GLPanels in 'Execute.FMX.GLPanels.pas', 8 | Execute.CubeMan in 'Execute.CubeMan.pas', 9 | Execute.CrossGL in 'Execute.CrossGL.pas', 10 | Execute.FMX.GLPanels.Types in 'Execute.FMX.GLPanels.Types.pas'; 11 | 12 | {$R *.res} 13 | 14 | begin 15 | Application.Initialize; 16 | Application.CreateForm(TMainForm, MainForm); 17 | Application.Run; 18 | end. 19 | -------------------------------------------------------------------------------- /GLPanel/GLPanelDemo.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/GLPanel/GLPanelDemo.res -------------------------------------------------------------------------------- /GLPanel/GlPanelMac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/GLPanel/GlPanelMac.png -------------------------------------------------------------------------------- /GLPanel/Main.fmx: -------------------------------------------------------------------------------- 1 | object MainForm: TMainForm 2 | Left = 0 3 | Top = 0 4 | Caption = 'OpenGL Panel' 5 | ClientHeight = 510 6 | ClientWidth = 466 7 | FormFactor.Width = 320 8 | FormFactor.Height = 480 9 | FormFactor.Devices = [Desktop] 10 | OnCreate = FormCreate 11 | DesignerMasterStyle = 0 12 | object Panel1: TPanel 13 | Align = Top 14 | Size.Width = 466.000000000000000000 15 | Size.Height = 49.000000000000000000 16 | Size.PlatformDefault = False 17 | TabOrder = 1 18 | object Label1: TLabel 19 | Position.X = 24.000000000000000000 20 | Position.Y = 8.000000000000000000 21 | Size.Width = 305.000000000000000000 22 | Size.Height = 33.000000000000000000 23 | Size.PlatformDefault = False 24 | Text = 'Cross platform TGLPanel for FMX (c)2017 Execute SARL' 25 | end 26 | end 27 | object Timer1: TTimer 28 | Interval = 40 29 | OnTimer = Timer1Timer 30 | Left = 192 31 | Top = 192 32 | end 33 | object Panel2: TPanel 34 | Align = Left 35 | Position.Y = 49.000000000000000000 36 | Size.Width = 65.000000000000000000 37 | Size.Height = 391.000000000000000000 38 | Size.PlatformDefault = False 39 | TabOrder = 4 40 | end 41 | object Panel3: TPanel 42 | Align = Bottom 43 | Position.Y = 440.000000000000000000 44 | Size.Width = 466.000000000000000000 45 | Size.Height = 70.000000000000000000 46 | Size.PlatformDefault = False 47 | TabOrder = 5 48 | end 49 | object Panel4: TPanel 50 | Align = Right 51 | Position.X = 413.000000000000000000 52 | Position.Y = 49.000000000000000000 53 | Size.Width = 53.000000000000000000 54 | Size.Height = 391.000000000000000000 55 | Size.PlatformDefault = False 56 | TabOrder = 6 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /GLPanel/Main.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/GLPanel/Main.pas -------------------------------------------------------------------------------- /GLPanel/readme.md: -------------------------------------------------------------------------------- 1 | #TGLPanel 2 | 3 | an OpenGL Panel for Firemonkey under Windows and OSX 4 | 5 | ![screenshot](GLPanel.png) ![screenshot](GlPanelMac.png) 6 | 7 | TPresentedControl is well explained in this article 8 | http://yaroslavbrovin.ru/new-approach-of-development-of-firemonkey-control-control-model-presentation-part-1-en/ 9 | 10 | -------------------------------------------------------------------------------- /Isometric/Isometric.dpr: -------------------------------------------------------------------------------- 1 | program Isometric; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | Main in 'Main.pas' {MainForm}; 7 | 8 | {$R *.res} 9 | 10 | begin 11 | Application.Initialize; 12 | Application.CreateForm(TMainForm, MainForm); 13 | Application.Run; 14 | end. 15 | -------------------------------------------------------------------------------- /Isometric/Isometric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/Isometric/Isometric.png -------------------------------------------------------------------------------- /Isometric/Isometric.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/Isometric/Isometric.res -------------------------------------------------------------------------------- /Isometric/Main.fmx: -------------------------------------------------------------------------------- 1 | object MainForm: TMainForm 2 | Left = 0 3 | Top = 0 4 | Caption = 'Isometric view under Firemonkey for Delphi Tokyo' 5 | Color = xFE000000 6 | ClientHeight = 571 7 | ClientWidth = 933 8 | FormFactor.Width = 320 9 | FormFactor.Height = 480 10 | FormFactor.Devices = [Desktop] 11 | OnRender = Form3DRender 12 | DesignerMasterStyle = 0 13 | end 14 | -------------------------------------------------------------------------------- /Isometric/Main.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/Isometric/Main.pas -------------------------------------------------------------------------------- /Isometric/readme.md: -------------------------------------------------------------------------------- 1 | # Isometric view under Firemonkey 2 | 3 | Firemonkey do not provide Isometric projection, but if you set the ContextState to cs2DScene, you can override the projection matrix with the "RenderToMatrix" matrix ! 4 | 5 | ![screenshot](Isometric.png) 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /MoreThan8Lights/FMXLights.dpr: -------------------------------------------------------------------------------- 1 | program FMXLights; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | Main in 'Main.pas' {Form1}; 7 | 8 | {$R *.res} 9 | 10 | begin 11 | Application.Initialize; 12 | Application.CreateForm(TForm1, Form1); 13 | Application.Run; 14 | end. 15 | -------------------------------------------------------------------------------- /MoreThan8Lights/FMXLights.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/MoreThan8Lights/FMXLights.res -------------------------------------------------------------------------------- /MoreThan8Lights/Main.fmx: -------------------------------------------------------------------------------- 1 | object Form1: TForm1 2 | Left = 0 3 | Top = 0 4 | Caption = 'Form1' 5 | ClientHeight = 583 6 | ClientWidth = 1177 7 | FormFactor.Width = 320 8 | FormFactor.Height = 480 9 | FormFactor.Devices = [Desktop] 10 | DesignerMasterStyle = 0 11 | object Viewport3D1: TViewport3D 12 | Position.X = 72.000000000000000000 13 | Position.Y = 40.000000000000000000 14 | Size.Width = 1009.000000000000000000 15 | Size.Height = 521.000000000000000000 16 | Size.PlatformDefault = False 17 | object Plane1: TPlane 18 | Position.X = -13.289526939392090000 19 | Position.Y = -2.696880817413330000 20 | Position.Z = 5.000000000000000000 21 | RotationAngle.X = 340.000000000000000000 22 | Width = 8.072472572326660000 23 | Height = 7.663682937622070000 24 | Depth = 0.001000000047497451 25 | SubdivisionsHeight = 10 26 | SubdivisionsWidth = 10 27 | MaterialSource = LightMaterialSource1 28 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 29 | object Light1: TLight 30 | Color = claWhite 31 | LightType = Spot 32 | SpotCutOff = 60.000000000000000000 33 | SpotExponent = 4.000000000000000000 34 | Position.Z = -4.000000000000000000 35 | RotationAngle.Y = 345.047607421875000000 36 | Width = 1.000000000000000000 37 | Height = 1.000000000000000000 38 | Depth = 1.000000000000000000 39 | Quanternion = '(0,0.212956428527832,0,-0.977061569690704)' 40 | end 41 | end 42 | object Plane2: TPlane 43 | Position.X = -4.686008453369141000 44 | Position.Y = -4.134114742279053000 45 | Position.Z = 5.000000000000000000 46 | RotationAngle.X = 340.000000000000000000 47 | Width = 8.072472572326660000 48 | Height = 7.663682937622070000 49 | Depth = 0.001000000047497451 50 | SubdivisionsHeight = 10 51 | SubdivisionsWidth = 10 52 | MaterialSource = LightMaterialSource1 53 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 54 | object Light2: TLight 55 | Color = claWhite 56 | LightType = Spot 57 | SpotCutOff = 60.000000000000000000 58 | SpotExponent = 4.000000000000000000 59 | Position.X = 0.624485969543457000 60 | Position.Y = 1.925696253776550000 61 | Position.Z = -3.299103498458862000 62 | RotationAngle.Y = 1.283422470092773000 63 | Width = 1.000000000000000000 64 | Height = 1.000000000000000000 65 | Depth = 1.000000000000000000 66 | Quanternion = '(0,-0.0111995469778776,0,-0.999936878681183)' 67 | end 68 | end 69 | object Plane3: TPlane 70 | Position.X = 3.908743143081665000 71 | Position.Y = -4.262164115905762000 72 | Position.Z = 5.000000000000000000 73 | RotationAngle.X = 340.000000000000000000 74 | Width = 8.072472572326660000 75 | Height = 7.663682937622070000 76 | Depth = 0.001000000047497451 77 | SubdivisionsHeight = 10 78 | SubdivisionsWidth = 10 79 | MaterialSource = LightMaterialSource1 80 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 81 | object Light3: TLight 82 | Color = claWhite 83 | LightType = Spot 84 | SpotCutOff = 60.000000000000000000 85 | SpotExponent = 4.000000000000000000 86 | Position.X = -1.169054508209229000 87 | Position.Y = 3.225466728210449000 88 | Position.Z = -3.113871097564697000 89 | RotationAngle.X = 19.724609375000000000 90 | Width = 1.000000000000000000 91 | Height = 1.000000000000000000 92 | Depth = 1.000000000000000000 93 | Quanternion = '(0.171279892325401,0,0,0.985222935676575)' 94 | end 95 | end 96 | object Plane4: TPlane 97 | Position.X = 12.693408012390140000 98 | Position.Y = -2.882531166076660000 99 | Position.Z = 5.000000000000000000 100 | RotationAngle.X = 340.000000000000000000 101 | Width = 8.072472572326660000 102 | Height = 7.663682937622070000 103 | Depth = 0.001000000047497451 104 | SubdivisionsHeight = 10 105 | SubdivisionsWidth = 10 106 | MaterialSource = LightMaterialSource1 107 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 108 | object Light4: TLight 109 | Color = claWhite 110 | LightType = Spot 111 | SpotCutOff = 60.000000000000000000 112 | SpotExponent = 4.000000000000000000 113 | Position.X = 0.072504639625549320 114 | Position.Y = -0.017682626843452450 115 | Position.Z = -4.294281959533691000 116 | Width = 1.000000000000000000 117 | Height = 1.000000000000000000 118 | Depth = 1.000000000000000000 119 | end 120 | end 121 | object Plane5: TPlane 122 | Position.X = -15.005095481872560000 123 | Position.Y = 6.844037532806396000 124 | Position.Z = 5.000000000000000000 125 | RotationAngle.X = 340.000000000000000000 126 | Width = 8.072472572326660000 127 | Height = 7.663682937622070000 128 | Depth = 0.001000000047497451 129 | SubdivisionsHeight = 10 130 | SubdivisionsWidth = 10 131 | MaterialSource = LightMaterialSource1 132 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 133 | object Light5: TLight 134 | Color = claWhite 135 | LightType = Spot 136 | SpotCutOff = 60.000000000000000000 137 | SpotExponent = 4.000000000000000000 138 | Position.X = 0.072504639625549320 139 | Position.Y = -0.017682626843452450 140 | Position.Z = -4.294281959533691000 141 | Width = 1.000000000000000000 142 | Height = 1.000000000000000000 143 | Depth = 1.000000000000000000 144 | end 145 | end 146 | object Plane6: TPlane 147 | Position.X = -7.242356777191162000 148 | Position.Y = 11.192867279052730000 149 | Position.Z = 5.000000000000000000 150 | RotationAngle.X = 340.000000000000000000 151 | Width = 8.072472572326660000 152 | Height = 7.663682937622070000 153 | Depth = 0.001000000047497451 154 | SubdivisionsHeight = 10 155 | SubdivisionsWidth = 10 156 | MaterialSource = LightMaterialSource1 157 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 158 | object Light6: TLight 159 | Color = claWhite 160 | LightType = Spot 161 | SpotCutOff = 60.000000000000000000 162 | SpotExponent = 4.000000000000000000 163 | Position.X = 2.210926532745361000 164 | Position.Y = -2.583330154418945000 165 | Position.Z = -5.228101730346680000 166 | Width = 1.000000000000000000 167 | Height = 1.000000000000000000 168 | Depth = 1.000000000000000000 169 | end 170 | end 171 | object Plane7: TPlane 172 | Position.X = 6.339773654937744000 173 | Position.Y = 10.366033554077150000 174 | Position.Z = 5.000000000000000000 175 | RotationAngle.X = 340.000000000000000000 176 | Width = 8.072472572326660000 177 | Height = 7.663682937622070000 178 | Depth = 0.001000000047497451 179 | SubdivisionsHeight = 10 180 | SubdivisionsWidth = 10 181 | MaterialSource = LightMaterialSource1 182 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 183 | object Light7: TLight 184 | Color = claWhite 185 | LightType = Spot 186 | SpotCutOff = 60.000000000000000000 187 | SpotExponent = 4.000000000000000000 188 | Position.X = -2.012195110321045000 189 | Position.Y = -1.893937706947327000 190 | Position.Z = -4.977183341979980000 191 | Width = 1.000000000000000000 192 | Height = 1.000000000000000000 193 | Depth = 1.000000000000000000 194 | end 195 | end 196 | object Plane8: TPlane 197 | Position.X = 14.763480186462400000 198 | Position.Y = 7.284362792968750000 199 | Position.Z = 4.999998092651367000 200 | RotationAngle.X = 340.000000000000000000 201 | Width = 8.072472572326660000 202 | Height = 7.663682937622070000 203 | Depth = 0.001000000047497451 204 | SubdivisionsHeight = 10 205 | SubdivisionsWidth = 10 206 | MaterialSource = LightMaterialSource1 207 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 208 | object Light8: TLight 209 | Color = claWhite 210 | LightType = Spot 211 | SpotCutOff = 60.000000000000000000 212 | SpotExponent = 4.000000000000000000 213 | Position.X = 0.072504639625549320 214 | Position.Y = -0.017682626843452450 215 | Position.Z = -4.294281959533691000 216 | Width = 1.000000000000000000 217 | Height = 1.000000000000000000 218 | Depth = 1.000000000000000000 219 | end 220 | end 221 | object Dummy1: TDummy 222 | Width = 1.000000000000000000 223 | Height = 1.000000000000000000 224 | Depth = 1.000000000000000000 225 | OnRender = Dummy1Render 226 | object Plane9: TPlane 227 | Position.X = -0.341574072837829600 228 | Position.Y = 3.916938304901123000 229 | Position.Z = 5.000000000000000000 230 | RotationAngle.X = 340.000000000000000000 231 | Width = 8.072472572326660000 232 | Height = 7.663682937622070000 233 | Depth = 0.001000000047497451 234 | SubdivisionsHeight = 10 235 | SubdivisionsWidth = 10 236 | MaterialSource = LightMaterialSource1 237 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 238 | object Light9: TLight 239 | Color = claWhite 240 | LightType = Spot 241 | SpotCutOff = 60.000000000000000000 242 | SpotExponent = 4.000000000000000000 243 | Position.Z = -4.000000000000000000 244 | Width = 1.000000000000000000 245 | Height = 1.000000000000000000 246 | Depth = 1.000000000000000000 247 | end 248 | end 249 | end 250 | end 251 | object LightMaterialSource1: TLightMaterialSource 252 | Diffuse = claWhite 253 | Ambient = xFF202020 254 | Emissive = claNull 255 | Specular = xFF606060 256 | Shininess = 30 257 | Left = 136 258 | Top = 24 259 | end 260 | end 261 | -------------------------------------------------------------------------------- /MoreThan8Lights/Main.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/MoreThan8Lights/Main.pas -------------------------------------------------------------------------------- /MoreThan8Lights/readme.md: -------------------------------------------------------------------------------- 1 | ## FMX Lights 2 | 3 | There's an hard coded limit of 8 simultaneous lights on a FMX Scene 4 | 5 | this demo shows a dirty hack to overflow this limitation. 6 | 7 | 9 planes with 9 lights in the IDE 8 | 9 | ![screen1.png](screen1.png) 10 | 11 | without the hack 12 | 13 | ![screen2.png](screen2.png) 14 | 15 | with the hack 16 | 17 | ![screen3.png](screen3.png) 18 | 19 | French explanations on Youtube 20 | 21 | [![Youtube](https://img.youtube.com/vi/fL5CmQdDTfg/0.jpg)](https://youtu.be/fL5CmQdDTfg) 22 | -------------------------------------------------------------------------------- /MoreThan8Lights/screen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/MoreThan8Lights/screen1.png -------------------------------------------------------------------------------- /MoreThan8Lights/screen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/MoreThan8Lights/screen2.png -------------------------------------------------------------------------------- /MoreThan8Lights/screen3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/MoreThan8Lights/screen3.png -------------------------------------------------------------------------------- /PuzzleSolver/readme.md: -------------------------------------------------------------------------------- 1 | ## PuzzleSolver 2 | 3 | 3D Puzzle Solver with Delphi 11 under Firemonkey 4 | 5 | Special video for Delphi's 27th Birthday ! 6 | 7 | [![Youtube](https://img.youtube.com/vi/9ttIgAJt7Bg/0.jpg)](https://www.youtube.com/watch?v=9ttIgAJt7Bg) -------------------------------------------------------------------------------- /PuzzleSolver/src/PuzzleSolver.Main.fmx: -------------------------------------------------------------------------------- 1 | object Main: TMain 2 | Left = 0 3 | Top = 0 4 | Caption = 'Puzzle Solver' 5 | ClientHeight = 583 6 | ClientWidth = 1035 7 | FormFactor.Width = 320 8 | FormFactor.Height = 480 9 | FormFactor.Devices = [Desktop] 10 | OnCreate = FormCreate 11 | DesignerMasterStyle = 0 12 | object Viewport3D1: TViewport3D 13 | Anchors = [akLeft, akTop, akRight, akBottom] 14 | Position.X = 16.000000000000000000 15 | Position.Y = 112.000000000000000000 16 | Size.Width = 889.000000000000000000 17 | Size.Height = 463.000000000000000000 18 | Size.PlatformDefault = False 19 | OnMouseDown = Viewport3D1MouseDown 20 | OnMouseMove = Viewport3D1MouseMove 21 | object Dummy1: TDummy 22 | Scale.X = 2.000000000000000000 23 | Scale.Y = 2.000000000000000000 24 | Scale.Z = 2.000000000000000000 25 | Width = 1.000000000000000000 26 | Height = 1.000000000000000000 27 | Depth = 1.000000000000000000 28 | object FloatAnimation1: TFloatAnimation 29 | Enabled = True 30 | Duration = 10.000000000000000000 31 | Loop = True 32 | PropertyName = 'RotationAngle.X' 33 | StartValue = 0.000000000000000000 34 | StopValue = 359.000000000000000000 35 | end 36 | object Dummy2: TDummy 37 | RotationAngle.Y = 20.000000000000000000 38 | Width = 1.000000000000000000 39 | Height = 1.000000000000000000 40 | Depth = 1.000000000000000000 41 | Quanternion = '(0,0.173648178577423,0,0.984807729721069)' 42 | object FloatAnimation2: TFloatAnimation 43 | Enabled = True 44 | Duration = 10.000000000000000000 45 | Loop = True 46 | PropertyName = 'RotationAngle.Y' 47 | StartValue = 0.000000000000000000 48 | StopValue = 359.000000000000000000 49 | end 50 | object Grid3D1: TGrid3D 51 | Marks = 1.000000000000000000 52 | Frequency = 1.000000000000000000 53 | LineColor = claSlategray 54 | Position.Z = -2.000000000000000000 55 | Width = 4.099999904632568000 56 | Height = 4.099999904632568000 57 | Depth = 0.001000000047497451 58 | HitTest = False 59 | VisibleContextMenu = False 60 | end 61 | object Grid3D2: TGrid3D 62 | Marks = 1.000000000000000000 63 | Frequency = 1.000000000000000000 64 | LineColor = claSlategray 65 | Position.Y = 2.000000000000000000 66 | RotationAngle.X = 90.000000000000000000 67 | Width = 4.099999904632568000 68 | Height = 4.099999904632568000 69 | Depth = 0.001000000047497451 70 | HitTest = False 71 | VisibleContextMenu = False 72 | Quanternion = '(0.70710676908493,0,0,0.70710676908493)' 73 | end 74 | object Grid3D3: TGrid3D 75 | Marks = 1.000000000000000000 76 | Frequency = 1.000000000000000000 77 | LineColor = claSlategray 78 | Position.Y = -2.000000000000000000 79 | RotationAngle.X = 90.000000000000000000 80 | Width = 4.099999904632568000 81 | Height = 4.099999904632568000 82 | Depth = 0.001000000047497451 83 | HitTest = False 84 | VisibleContextMenu = False 85 | Quanternion = '(0.70710676908493,0,0,0.70710676908493)' 86 | end 87 | object Grid3D4: TGrid3D 88 | Marks = 1.000000000000000000 89 | Frequency = 1.000000000000000000 90 | LineColor = claSlategray 91 | Position.Z = 2.000000000000000000 92 | Width = 4.099999904632568000 93 | Height = 4.099999904632568000 94 | Depth = 0.001000000047497451 95 | HitTest = False 96 | VisibleContextMenu = False 97 | end 98 | object Grid3D5: TGrid3D 99 | Marks = 1.000000000000000000 100 | Frequency = 1.000000000000000000 101 | LineColor = claSlategray 102 | Position.X = 2.000000000000000000 103 | RotationAngle.Y = 90.000000000000000000 104 | Width = 4.099999904632568000 105 | Height = 4.099999904632568000 106 | Depth = 0.001000000047497451 107 | HitTest = False 108 | VisibleContextMenu = False 109 | Quanternion = '(0,0.70710676908493,0,0.70710676908493)' 110 | end 111 | object Grid3D6: TGrid3D 112 | Marks = 1.000000000000000000 113 | Frequency = 1.000000000000000000 114 | LineColor = claSlategray 115 | Position.X = -2.000000000000000000 116 | RotationAngle.Y = 90.000000000000000000 117 | Width = 4.099999904632568000 118 | Height = 4.099999904632568000 119 | Depth = 0.001000000047497451 120 | HitTest = False 121 | VisibleContextMenu = False 122 | Quanternion = '(0,0.70710676908493,0,0.70710676908493)' 123 | end 124 | end 125 | end 126 | object Light1: TLight 127 | Color = claWhite 128 | LightType = Directional 129 | SpotCutOff = 180.000000000000000000 130 | Position.X = -7.494535923004150000 131 | Position.Y = -5.105115890502930000 132 | RotationAngle.X = 313.606384277343800000 133 | RotationAngle.Y = 18.971349716186520000 134 | RotationAngle.Z = 4.719841003417969000 135 | Width = 1.000000000000000000 136 | Height = 1.000000000000000000 137 | Depth = 1.000000000000000000 138 | Quanternion = 139 | '(-0.38193815946579,0.169022768735886,0.0139321302995086,0.908493' + 140 | '459224701)' 141 | end 142 | end 143 | object Pie1: TPie 144 | Position.X = 16.000000000000000000 145 | Position.Y = 16.000000000000000000 146 | Size.Width = 50.000000000000000000 147 | Size.Height = 50.000000000000000000 148 | Size.PlatformDefault = False 149 | StartAngle = -90.000000000000000000 150 | EndAngle = 359.000000000000000000 151 | end 152 | object Pie2: TPie 153 | Position.X = 74.000000000000000000 154 | Position.Y = 16.000000000000000000 155 | Size.Width = 50.000000000000000000 156 | Size.Height = 50.000000000000000000 157 | Size.PlatformDefault = False 158 | StartAngle = -90.000000000000000000 159 | EndAngle = 359.000000000000000000 160 | end 161 | object Pie3: TPie 162 | Position.X = 132.000000000000000000 163 | Position.Y = 16.000000000000000000 164 | Size.Width = 50.000000000000000000 165 | Size.Height = 50.000000000000000000 166 | Size.PlatformDefault = False 167 | StartAngle = -90.000000000000000000 168 | EndAngle = 359.000000000000000000 169 | end 170 | object Pie4: TPie 171 | Position.X = 190.000000000000000000 172 | Position.Y = 16.000000000000000000 173 | Size.Width = 50.000000000000000000 174 | Size.Height = 50.000000000000000000 175 | Size.PlatformDefault = False 176 | StartAngle = -90.000000000000000000 177 | EndAngle = 359.000000000000000000 178 | end 179 | object Pie5: TPie 180 | Position.X = 248.000000000000000000 181 | Position.Y = 16.000000000000000000 182 | Size.Width = 50.000000000000000000 183 | Size.Height = 50.000000000000000000 184 | Size.PlatformDefault = False 185 | StartAngle = -90.000000000000000000 186 | EndAngle = 359.000000000000000000 187 | end 188 | object Pie6: TPie 189 | Position.X = 306.000000000000000000 190 | Position.Y = 16.000000000000000000 191 | Size.Width = 50.000000000000000000 192 | Size.Height = 50.000000000000000000 193 | Size.PlatformDefault = False 194 | StartAngle = -90.000000000000000000 195 | EndAngle = 359.000000000000000000 196 | end 197 | object Pie7: TPie 198 | Position.X = 364.000000000000000000 199 | Position.Y = 16.000000000000000000 200 | Size.Width = 50.000000000000000000 201 | Size.Height = 50.000000000000000000 202 | Size.PlatformDefault = False 203 | StartAngle = -90.000000000000000000 204 | EndAngle = 359.000000000000000000 205 | end 206 | object Pie8: TPie 207 | Position.X = 422.000000000000000000 208 | Position.Y = 16.000000000000000000 209 | Size.Width = 50.000000000000000000 210 | Size.Height = 50.000000000000000000 211 | Size.PlatformDefault = False 212 | StartAngle = -90.000000000000000000 213 | EndAngle = 359.000000000000000000 214 | end 215 | object Pie9: TPie 216 | Position.X = 480.000000000000000000 217 | Position.Y = 16.000000000000000000 218 | Size.Width = 50.000000000000000000 219 | Size.Height = 50.000000000000000000 220 | Size.PlatformDefault = False 221 | StartAngle = -90.000000000000000000 222 | EndAngle = 359.000000000000000000 223 | end 224 | object Pie10: TPie 225 | Position.X = 538.000000000000000000 226 | Position.Y = 16.000000000000000000 227 | Size.Width = 50.000000000000000000 228 | Size.Height = 50.000000000000000000 229 | Size.PlatformDefault = False 230 | StartAngle = -90.000000000000000000 231 | EndAngle = 359.000000000000000000 232 | end 233 | object TrackBar1: TTrackBar 234 | CanParentFocus = True 235 | Max = 50000000.000000000000000000 236 | Orientation = Horizontal 237 | Position.X = 16.000000000000000000 238 | Position.Y = 80.000000000000000000 239 | Size.Width = 572.000000000000000000 240 | Size.Height = 19.000000000000000000 241 | Size.PlatformDefault = False 242 | TabOrder = 17 243 | end 244 | object Button2: TButton 245 | Position.X = 929.000000000000000000 246 | Position.Y = 112.000000000000000000 247 | Size.Width = 80.000000000000000000 248 | Size.Height = 41.000000000000000000 249 | Size.PlatformDefault = False 250 | TabOrder = 18 251 | Text = 'Stop' 252 | OnClick = Button2Click 253 | end 254 | object CheckBox2: TCheckBox 255 | Tag = 1 256 | IsChecked = True 257 | Position.X = 929.000000000000000000 258 | Position.Y = 203.000000000000000000 259 | Size.Width = 88.000000000000000000 260 | Size.Height = 19.000000000000000000 261 | Size.PlatformDefault = False 262 | TabOrder = 12 263 | Text = '2' 264 | OnChange = CheckBox1Change 265 | end 266 | object CheckBox3: TCheckBox 267 | Tag = 2 268 | IsChecked = True 269 | Position.X = 929.000000000000000000 270 | Position.Y = 230.000000000000000000 271 | Size.Width = 88.000000000000000000 272 | Size.Height = 19.000000000000000000 273 | Size.PlatformDefault = False 274 | TabOrder = 9 275 | Text = '3' 276 | OnChange = CheckBox1Change 277 | end 278 | object CheckBox1: TCheckBox 279 | IsChecked = True 280 | Position.X = 929.000000000000000000 281 | Position.Y = 176.000000000000000000 282 | Size.Width = 88.000000000000000000 283 | Size.Height = 19.000000000000000000 284 | Size.PlatformDefault = False 285 | TabOrder = 20 286 | Text = '1' 287 | OnChange = CheckBox1Change 288 | end 289 | object CheckBox4: TCheckBox 290 | Tag = 3 291 | IsChecked = True 292 | Position.X = 929.000000000000000000 293 | Position.Y = 257.000000000000000000 294 | Size.Width = 88.000000000000000000 295 | Size.Height = 19.000000000000000000 296 | Size.PlatformDefault = False 297 | TabOrder = 19 298 | Text = '4' 299 | OnChange = CheckBox1Change 300 | end 301 | object CheckBox5: TCheckBox 302 | Tag = 4 303 | IsChecked = True 304 | Position.X = 929.000000000000000000 305 | Position.Y = 284.000000000000000000 306 | Size.Width = 88.000000000000000000 307 | Size.Height = 19.000000000000000000 308 | Size.PlatformDefault = False 309 | TabOrder = 11 310 | Text = '5' 311 | OnChange = CheckBox1Change 312 | end 313 | object CheckBox6: TCheckBox 314 | Tag = 5 315 | IsChecked = True 316 | Position.X = 929.000000000000000000 317 | Position.Y = 311.000000000000000000 318 | Size.Width = 88.000000000000000000 319 | Size.Height = 19.000000000000000000 320 | Size.PlatformDefault = False 321 | TabOrder = 8 322 | Text = '6' 323 | OnChange = CheckBox1Change 324 | end 325 | object CheckBox7: TCheckBox 326 | Tag = 6 327 | IsChecked = True 328 | Position.X = 929.000000000000000000 329 | Position.Y = 338.000000000000000000 330 | Size.Width = 88.000000000000000000 331 | Size.Height = 19.000000000000000000 332 | Size.PlatformDefault = False 333 | TabOrder = 6 334 | Text = '7' 335 | OnChange = CheckBox1Change 336 | end 337 | object CheckBox8: TCheckBox 338 | Tag = 7 339 | IsChecked = True 340 | Position.X = 929.000000000000000000 341 | Position.Y = 365.000000000000000000 342 | Size.Width = 88.000000000000000000 343 | Size.Height = 19.000000000000000000 344 | Size.PlatformDefault = False 345 | TabOrder = 10 346 | Text = '8' 347 | OnChange = CheckBox1Change 348 | end 349 | object CheckBox9: TCheckBox 350 | Tag = 8 351 | IsChecked = True 352 | Position.X = 929.000000000000000000 353 | Position.Y = 392.000000000000000000 354 | Size.Width = 88.000000000000000000 355 | Size.Height = 19.000000000000000000 356 | Size.PlatformDefault = False 357 | TabOrder = 7 358 | Text = '9' 359 | OnChange = CheckBox1Change 360 | end 361 | object CheckBox10: TCheckBox 362 | Tag = 9 363 | IsChecked = True 364 | Position.X = 929.000000000000000000 365 | Position.Y = 419.000000000000000000 366 | Size.Width = 88.000000000000000000 367 | Size.Height = 19.000000000000000000 368 | Size.PlatformDefault = False 369 | TabOrder = 5 370 | Text = '10' 371 | OnChange = CheckBox1Change 372 | end 373 | end 374 | -------------------------------------------------------------------------------- /PuzzleSolver/src/PuzzleSolver.Main.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/PuzzleSolver/src/PuzzleSolver.Main.pas -------------------------------------------------------------------------------- /PuzzleSolver/src/PuzzleSolver.dpr: -------------------------------------------------------------------------------- 1 | program PuzzleSolver; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | PuzzleSolver.Main in 'PuzzleSolver.Main.pas' {Main}; 7 | 8 | {$R *.res} 9 | 10 | begin 11 | Application.Initialize; 12 | Application.CreateForm(TMain, Main); 13 | Application.Run; 14 | end. 15 | -------------------------------------------------------------------------------- /PuzzleSolver/src/PuzzleSolver.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/PuzzleSolver/src/PuzzleSolver.res -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Firemonkey 2 | Firemonkey source code by Execute SARL 3 | -------------------------------------------------------------------------------- /SourceShaders/Execute.ShaderMaterial.pas: -------------------------------------------------------------------------------- 1 | unit Execute.ShaderMaterial; 2 | 3 | { 4 | Sample Shader compiler (c)2019 Execute SARL 5 | 6 | } 7 | 8 | interface 9 | 10 | uses 11 | System.SysUtils, 12 | System.Classes, 13 | System.Math.Vectors, 14 | FMX.Types3D, 15 | FMX.Materials, 16 | FMX.MaterialSources; 17 | 18 | const 19 | DEFAULT_VERTEX_SHADER = 20 | {$IFDEF MSWINDOWS} 21 | 'matrix MVPMatrix;'+ 22 | // input parameters 23 | 'struct Input {'+ 24 | ' float4 p: POSITION;'+ 25 | ' float2 t: TEXCOORD0;'+ 26 | '};'+ 27 | // output parameters 28 | 'struct Output {'+ 29 | ' float4 p: POSITION;'+ 30 | ' float2 t: TEXCOORD0;'+ 31 | '};'+ 32 | // main program 33 | 'Output main(Input input) {'+ 34 | ' Output output;'+ 35 | ' output.p = mul(MVPMatrix, input.p);'+ 36 | ' output.t = input.t;'+ 37 | ' return output;'+ 38 | '}'; 39 | {$ELSE} 40 | 'uniform mat4 _MVPMatrix;'+ 41 | // Input 42 | 'attribute vec2 a_TexCoord0;'+ 43 | 'attribute vec4 a_Position;'+ 44 | // Interpolation 45 | 'varying vec2 t;'+ 46 | // main program 47 | 'void main() {'+ 48 | ' t = a_TexCoord0;'+ 49 | ' gl_Position = _MVPMatrix * a_Position;'+ 50 | '}'; 51 | {$ENDIF} 52 | 53 | type 54 | TApplyShaderEvent = procedure(Sender: TObject; Context: TContext3D) of object; 55 | 56 | TShaderMaterial = class(TCustomMaterial) 57 | private 58 | FVertexShaderSource: string; 59 | FPixelShaderSource : string; 60 | FVertexShaderBytes : TBytes; 61 | FPixelShaderBytes : TBytes; 62 | FPixelShaderVars : TContextShaderVariables; 63 | MVPMatrix : TContextShaderVariable; 64 | FOnApply : TApplyShaderEvent; 65 | procedure SetVertexShader(const Value: string); 66 | procedure SetPixelShader(const Value: string); 67 | protected 68 | procedure DoInitialize; override; 69 | procedure DoApply(const Context: TContext3D); override; 70 | class function DoGetMaterialProperty(const Prop: TMaterial.TProperty): string; override; 71 | public 72 | constructor Create(const AVertexShader, APixelShader: string; const APixelShaderVars: TContextShaderVariables); reintroduce; 73 | property OnApply: TApplyShaderEvent read FOnApply write FOnApply; 74 | property VertexShader: string read FVertexShaderSource write SetVertexShader; 75 | property PixelShader: string read FPixelShaderSource write SetPixelShader; 76 | end; 77 | 78 | TShaderMaterialSource = class(TMaterialSource) 79 | private 80 | function GetVertexShader: string; 81 | procedure SetVertexShader(const Value: string); 82 | function GetPixelShader: string; 83 | procedure SetPixelShader(const Value: string); 84 | protected 85 | function CreateMaterial: TMaterial; override; 86 | public 87 | property VertexShader: string read GetVertexShader write SetVertexShader; 88 | property PixelShader: string read GetPixelShader write SetPixelShader; 89 | end; 90 | 91 | implementation 92 | 93 | {$IFDEF MSWINDOWS} 94 | uses 95 | Winapi.D3DCommon, 96 | Winapi.D3DCompiler; 97 | 98 | function DXCompile(const Source: string; Kind: TContextShaderKind; Arch: TContextShaderArch = TContextShaderArch.DX11): TBytes; 99 | var 100 | Data : TBytes; 101 | Target : AnsiString; 102 | Flags : Cardinal; 103 | Code : ID3DBlob; 104 | Err : ID3DBlob; 105 | Str : string; 106 | begin 107 | Data := TEncoding.ANSI.GetBytes(Source); 108 | case Arch of 109 | TContextShaderArch.DX11_level_9: Target := '2_0'; // D3D_FEATURE_LEVEL_9_1 110 | TContextShaderArch.DX10 : Target := '4_0'; // D3D_FEATURE_LEVEL_10_0 111 | TContextShaderArch.DX11 : Target := '5_0'; // D3D_FEATURE_LEVEL_11_0 112 | else 113 | raise Exception.Create('Unsupported architecture'); 114 | end; 115 | case Kind of 116 | TContextShaderKind.VertexShader: Target := 'vs_' + Target; 117 | TContextShaderKind.PixelShader : Target := 'ps_' + Target; 118 | end; 119 | 120 | Flags := D3DCOMPILE_OPTIMIZATION_LEVEL3 121 | // or D3DCOMPILE_ENABLE_STRICTNESS 122 | or D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY 123 | or D3DCOMPILE_WARNINGS_ARE_ERRORS; 124 | 125 | if D3DCompile(Data, Length(Data), nil, nil, nil, 'main', PAnsiChar(Target), Flags, 0, Code, Err) = 0 then 126 | begin 127 | SetLength(Result, Code.GetBufferSize); 128 | Move(Code.GetBufferPointer^, Result[0], Length(Result)); 129 | end else begin 130 | SetString(Str, PAnsiChar(Err.GetBufferPointer), Err.GetBufferSize); 131 | raise Exception.Create('Shader compilation error :'#13 + Str); 132 | end; 133 | end; 134 | {$ENDIF} 135 | 136 | {$IFDEF OSX} 137 | uses 138 | Macapi.CocoaTypes, 139 | Macapi.OpenGL; 140 | {$ENDIF} 141 | {$IFDEF ANDROID} 142 | uses 143 | Androidapi.Gles2; 144 | {$ENDIF} 145 | 146 | { TShaderMaterial } 147 | 148 | const 149 | ARCH = {$IFDEF MSWINDOWS}TContextShaderArch.DX11{$ELSE}TContextShaderArch.GLSL{$ENDIF}; 150 | 151 | constructor TShaderMaterial.Create(const AVertexShader, APixelShader: string; const APixelShaderVars: TContextShaderVariables); 152 | begin 153 | VertexShader := AVertexShader; 154 | PixelShader := APixelShader; 155 | FPixelShaderVars := APixelShaderVars; 156 | inherited Create; 157 | end; 158 | 159 | procedure TShaderMaterial.DoInitialize; 160 | begin 161 | // Why is the MaterialShader initialized from the constructor !!!! 162 | if (FVertexShaderBytes = nil) or (FPixelShaderBytes = nil) then 163 | Exit; 164 | 165 | inherited; 166 | 167 | MVPMatrix := TContextShaderVariable.Create('MVPMatrix', TContextShaderVariableKind.Matrix, 0, 64); 168 | FVertexShader := TShaderManager.RegisterShaderFromData( 169 | '', 170 | TContextShaderKind.VertexShader, 171 | '', 172 | [TContextShaderSource.Create(ARCH, FVertexShaderBytes,[MVPMatrix])] 173 | ); 174 | FPixelShader := TShaderManager.RegisterShaderFromData( 175 | '', TContextShaderKind.PixelShader, '', 176 | [TContextShaderSource.Create(ARCH, FPixelShaderBytes, FPixelShaderVars)] 177 | ); 178 | end; 179 | 180 | procedure TShaderMaterial.SetPixelShader(const Value: string); 181 | begin 182 | if Value <> FPixelShaderSource then 183 | begin 184 | FPixelShaderSource := Value; 185 | if FPixelShaderSource = '' then 186 | FPixelShaderBytes := nil 187 | else begin 188 | {$IFDEF MSWINDOWS} 189 | FPixelShaderBytes := DXCompile(FPixelShaderSource, TContextShaderKind.PixelShader); 190 | {$ELSE} 191 | FPixelShaderBytes := TEncoding.ANSI.GetBytes(FPixelShaderSource); 192 | {$ENDIF} 193 | DoInitialize; 194 | end; 195 | end; 196 | end; 197 | 198 | procedure TShaderMaterial.SetVertexShader(const Value: string); 199 | begin 200 | if Value <> FVertexShaderSource then 201 | begin 202 | FVertexShaderSource := Value; 203 | if FVertexShaderSource = '' then 204 | FVertexShaderBytes := nil 205 | else begin 206 | {$IFDEF MSWINDOWS} 207 | FVertexShaderBytes := DXCompile(FVertexShaderSource, TContextShaderKind.VertexShader); 208 | {$ELSE} 209 | FVertexShaderBytes := TEncoding.ANSI.GetBytes(FVertexShaderSource); 210 | {$ENDIF} 211 | DoInitialize; 212 | end; 213 | end; 214 | end; 215 | 216 | procedure TShaderMaterial.DoApply(const Context: TContext3D); 217 | {$IFNDEF MSWINDOWS} 218 | var 219 | M: TMatrix3D; 220 | {$ENDIF} 221 | begin 222 | inherited; 223 | {$IFNDEF MSWINDOWS} 224 | // https://quality.embarcadero.com/browse/RSP-16323 225 | M := Context.CurrentModelViewProjectionMatrix; 226 | glUniformMatrix4fv(MVPMatrix.Index, 1, GL_FALSE, @M.m11); 227 | {$ENDIF} 228 | if Assigned(FOnApply) then 229 | FOnApply(Self, Context); 230 | end; 231 | 232 | class function TShaderMaterial.DoGetMaterialProperty( 233 | const Prop: TMaterial.TProperty): string; 234 | begin 235 | {$IFDEF MSWINDOWS} 236 | // https://quality.embarcadero.com/browse/RSP-16323 237 | if Prop = TProperty.ModelViewProjection then 238 | begin 239 | Exit('MVPMatrix'); 240 | end; 241 | {$ENDIF} 242 | Result := ''; 243 | end; 244 | 245 | { TShaderMaterialSource } 246 | 247 | function TShaderMaterialSource.CreateMaterial: TMaterial; 248 | begin 249 | Result := TShaderMaterial.Create('', '', []); 250 | end; 251 | 252 | function TShaderMaterialSource.GetPixelShader: string; 253 | begin 254 | Result := TShaderMaterial(Material).PixelShader; 255 | end; 256 | 257 | function TShaderMaterialSource.GetVertexShader: string; 258 | begin 259 | Result := TShaderMaterial(Material).VertexShader; 260 | end; 261 | 262 | procedure TShaderMaterialSource.SetPixelShader(const Value: string); 263 | begin 264 | TShaderMaterial(Material).PixelShader := Value; 265 | end; 266 | 267 | procedure TShaderMaterialSource.SetVertexShader(const Value: string); 268 | begin 269 | TShaderMaterial(Material).VertexShader := Value; 270 | end; 271 | 272 | end. 273 | -------------------------------------------------------------------------------- /SourceShaders/Form1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/SourceShaders/Form1.png -------------------------------------------------------------------------------- /SourceShaders/Main.fmx: -------------------------------------------------------------------------------- 1 | object Form1: TForm1 2 | Left = 0 3 | Top = 0 4 | Caption = 'TShaderMaterial demo (c)2019 Execute SARL' 5 | ClientHeight = 566 6 | ClientWidth = 876 7 | FormFactor.Width = 320 8 | FormFactor.Height = 480 9 | FormFactor.Devices = [Desktop] 10 | OnCreate = Form3DCreate 11 | DesignerMasterStyle = 0 12 | object Timer1: TTimer 13 | Interval = 33 14 | OnTimer = Timer1Timer 15 | end 16 | object Plane2: TPlane 17 | Position.X = -6.673500537872314000 18 | Position.Y = -3.909884214401245000 19 | RotationAngle.X = 340.000000000000000000 20 | Width = 9.418337821960449000 21 | Height = 6.704707622528076000 22 | Depth = 0.001000000047497451 23 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 24 | end 25 | object Plane3: TPlane 26 | Position.X = -8.095270156860352000 27 | Position.Y = 3.663649082183838000 28 | RotationAngle.X = 340.000000000000000000 29 | Width = 4.736832618713379000 30 | Height = 4.300696372985840000 31 | Depth = 0.001000000047497451 32 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 33 | end 34 | object Plane4: TPlane 35 | Position.X = 5.363698959350586000 36 | Position.Y = 5.243049144744873000 37 | RotationAngle.X = 340.000000000000000000 38 | Width = 9.418337821960449000 39 | Height = 6.704707622528076000 40 | Depth = 0.001000000047497451 41 | Quanternion = '(0.173648297786713,0,0,-0.984807729721069)' 42 | end 43 | object Plane1: TPlane 44 | Position.X = 4.807112693786621000 45 | Position.Y = -2.776535034179688000 46 | Width = 10.629789352416990000 47 | Height = 7.298233985900879000 48 | Depth = 0.001000000047497451 49 | object FloatAnimation1: TFloatAnimation 50 | Enabled = True 51 | Duration = 5.000000000000000000 52 | Loop = True 53 | PropertyName = 'RotationAngle.X' 54 | StartValue = 0.000000000000000000 55 | StopValue = 360.000000000000000000 56 | end 57 | object FloatAnimation2: TFloatAnimation 58 | Enabled = True 59 | Duration = 10.000000000000000000 60 | Loop = True 61 | PropertyName = 'RotationAngle.Y' 62 | StartValue = 0.000000000000000000 63 | StopValue = 360.000000000000000000 64 | end 65 | object FloatAnimation3: TFloatAnimation 66 | Enabled = True 67 | Duration = 20.000000000000000000 68 | Loop = True 69 | PropertyName = 'RotationAngle.Z' 70 | StartValue = 0.000000000000000000 71 | StopValue = 360.000000000000000000 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /SourceShaders/Main.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/SourceShaders/Main.pas -------------------------------------------------------------------------------- /SourceShaders/ShaderSource.dpr: -------------------------------------------------------------------------------- 1 | program ShaderSource; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | Main in 'Main.pas' {Form1}, 7 | Execute.ShaderMaterial in 'Execute.ShaderMaterial.pas'; 8 | 9 | {$R *.res} 10 | 11 | begin 12 | Application.Initialize; 13 | Application.CreateForm(TForm1, Form1); 14 | Application.Run; 15 | end. 16 | -------------------------------------------------------------------------------- /SourceShaders/readme.md: -------------------------------------------------------------------------------- 1 | # SourceShader 2 | 3 | Sample FMX component to use a Shader as a MaterialSource 4 | 5 | tested with Dephi Rio 10.3.3 under Windows, OSX and Android ! 6 | 7 | you can use directly either a HLSL (DirectX under Windows) or GLSL (OpenGL on other platforms) source code. 8 | ``` 9 | const 10 | PIXEL_SHADER = 11 | {$IFDEF MSWINDOWS} 12 | ' float4 main() : COLOR {' 13 | + ' return float4(1.0, 0.5, 0.5, 1.0);' 14 | + '}'; 15 | {$ELSE} 16 | 'void main() {'+ 17 | ' gl_FragColor = vec4(1.0, 0.5, 0.5, 1.0);'+ 18 | '}'; 19 | {$ENDIF} 20 | ``` 21 | ![Form1](Form1.png) -------------------------------------------------------------------------------- /TextPath/Execute.FMX.TextPath.fmx: -------------------------------------------------------------------------------- 1 | object TextPathEditor: TTextPathEditor 2 | Left = 0 3 | Top = 0 4 | ClientHeight = 372 5 | ClientWidth = 627 6 | FormFactor.Width = 320 7 | FormFactor.Height = 480 8 | FormFactor.Devices = [Desktop, iPhone, iPad] 9 | OnCreate = FormCreate 10 | DesignerMasterStyle = 0 11 | object Layout1: TLayout 12 | Align = Top 13 | Size.Width = 627.000000000000000000 14 | Size.Height = 41.000000000000000000 15 | Size.PlatformDefault = False 16 | TabOrder = 1 17 | object edText: TEdit 18 | Touch.InteractiveGestures = [LongTap, DoubleTap] 19 | Anchors = [akLeft, akTop, akRight] 20 | TabOrder = 2 21 | Text = 'Sample Text' 22 | Position.X = 208.000000000000000000 23 | Position.Y = 8.000000000000000000 24 | Size.Width = 406.000000000000000000 25 | Size.Height = 22.000000000000000000 26 | Size.PlatformDefault = False 27 | OnChange = edTextChange 28 | object Label2: TLabel 29 | Position.X = -47.000000000000000000 30 | Size.Width = 40.000000000000000000 31 | Size.Height = 22.000000000000000000 32 | Size.PlatformDefault = False 33 | Text = 'Text' 34 | TabOrder = 0 35 | end 36 | end 37 | object Label1: TLabel 38 | Position.X = 8.000000000000000000 39 | Position.Y = 8.000000000000000000 40 | Size.Width = 41.000000000000000000 41 | Size.Height = 22.000000000000000000 42 | Size.PlatformDefault = False 43 | Text = 'Font' 44 | TabOrder = 0 45 | end 46 | object edSize: TEdit 47 | Touch.InteractiveGestures = [LongTap, DoubleTap] 48 | TabOrder = 1 49 | Text = '1024' 50 | Position.X = 96.000000000000000000 51 | Position.Y = 8.000000000000000000 52 | Size.Width = 57.000000000000000000 53 | Size.Height = 22.000000000000000000 54 | Size.PlatformDefault = False 55 | OnChange = edTextChange 56 | object Label3: TLabel 57 | Position.X = -32.000000000000000000 58 | Size.Width = 25.000000000000000000 59 | Size.Height = 22.000000000000000000 60 | Size.PlatformDefault = False 61 | Text = 'Size' 62 | TabOrder = 0 63 | end 64 | end 65 | end 66 | object Path: TPath 67 | Align = Client 68 | Margins.Left = 5.000000000000000000 69 | Margins.Top = 5.000000000000000000 70 | Margins.Right = 5.000000000000000000 71 | Margins.Bottom = 5.000000000000000000 72 | Size.Width = 464.000000000000000000 73 | Size.Height = 277.000000000000000000 74 | Size.PlatformDefault = False 75 | end 76 | object lbFonts: TListBox 77 | Align = Left 78 | Position.Y = 41.000000000000000000 79 | Size.Width = 153.000000000000000000 80 | Size.Height = 287.000000000000000000 81 | Size.PlatformDefault = False 82 | TabOrder = 3 83 | DisableFocusEffect = True 84 | DefaultItemStyles.ItemStyle = '' 85 | DefaultItemStyles.GroupHeaderStyle = '' 86 | DefaultItemStyles.GroupFooterStyle = '' 87 | OnChange = edTextChange 88 | Viewport.Width = 149.000000000000000000 89 | Viewport.Height = 283.000000000000000000 90 | end 91 | object Layout2: TLayout 92 | Align = Bottom 93 | Position.Y = 328.000000000000000000 94 | Size.Width = 627.000000000000000000 95 | Size.Height = 44.000000000000000000 96 | Size.PlatformDefault = False 97 | TabOrder = 4 98 | object Button1: TButton 99 | Align = Right 100 | ModalResult = 1 101 | Margins.Left = 5.000000000000000000 102 | Margins.Top = 5.000000000000000000 103 | Margins.Right = 5.000000000000000000 104 | Margins.Bottom = 5.000000000000000000 105 | Position.X = 419.000000000000000000 106 | Position.Y = 5.000000000000000000 107 | Size.Width = 105.000000000000000000 108 | Size.Height = 34.000000000000000000 109 | Size.PlatformDefault = False 110 | TabOrder = 0 111 | Text = 'OK' 112 | end 113 | object Button2: TButton 114 | Align = Right 115 | ModalResult = 2 116 | Margins.Left = 5.000000000000000000 117 | Margins.Top = 5.000000000000000000 118 | Margins.Right = 5.000000000000000000 119 | Margins.Bottom = 5.000000000000000000 120 | Position.X = 534.000000000000000000 121 | Position.Y = 5.000000000000000000 122 | Size.Width = 88.000000000000000000 123 | Size.Height = 34.000000000000000000 124 | Size.PlatformDefault = False 125 | TabOrder = 1 126 | Text = 'Cancel' 127 | end 128 | object cbBold: TCheckBox 129 | Position.X = 16.000000000000000000 130 | Position.Y = 16.000000000000000000 131 | Size.Width = 73.000000000000000000 132 | Size.Height = 19.000000000000000000 133 | Size.PlatformDefault = False 134 | TabOrder = 3 135 | Text = 'Bold' 136 | OnChange = edTextChange 137 | end 138 | object cbItalic: TCheckBox 139 | Position.X = 88.000000000000000000 140 | Position.Y = 16.000000000000000000 141 | Size.Width = 73.000000000000000000 142 | Size.Height = 19.000000000000000000 143 | Size.PlatformDefault = False 144 | TabOrder = 2 145 | Text = 'Italic' 146 | OnChange = edTextChange 147 | end 148 | end 149 | end 150 | -------------------------------------------------------------------------------- /TextPath/Execute.FMX.TextPath.pas: -------------------------------------------------------------------------------- 1 | unit Execute.FMX.TextPath; 2 | { 3 | Create a vectorial text in a FMX TPath (c)2017 Execute SARL 4 | http://www.execute.fr 5 | 6 | } 7 | interface 8 | 9 | uses 10 | System.Classes, 11 | System.SysUtils, 12 | System.UITypes, 13 | DesignEditors, 14 | DesignIntf, 15 | FMX.Forms, FMX.Layouts, FMX.Types, FMX.Controls, 16 | FMX.Edit, FMX.Controls.Presentation, FMX.StdCtrls, FMX.ListBox, FMX.Objects; 17 | 18 | type 19 | TPathEditor = class(TComponentEditor) 20 | function GetVerb(Index: Integer): string; override; 21 | function GetVerbCount: Integer; override; 22 | procedure ExecuteVerb(Index: Integer); override; 23 | end; 24 | 25 | TTextPathEditor = class(TForm) 26 | Layout1: TLayout; 27 | Label2: TLabel; 28 | edText: TEdit; 29 | Path: TPath; 30 | Label1: TLabel; 31 | lbFonts: TListBox; 32 | Layout2: TLayout; 33 | Button1: TButton; 34 | Button2: TButton; 35 | edSize: TEdit; 36 | Label3: TLabel; 37 | cbBold: TCheckBox; 38 | cbItalic: TCheckBox; 39 | procedure FormCreate(Sender: TObject); 40 | procedure edTextChange(Sender: TObject); 41 | public 42 | class procedure Edit(APath: TPath); 43 | end; 44 | 45 | procedure Register; 46 | 47 | implementation 48 | 49 | {$R *.fmx} 50 | 51 | uses 52 | Execute.FontBuilder; 53 | 54 | procedure Register; 55 | begin 56 | RegisterComponentEditor(TPath, TPathEditor); 57 | end; 58 | 59 | { TPathEditor } 60 | 61 | procedure TPathEditor.ExecuteVerb(Index: Integer); 62 | var 63 | Path: TPath; 64 | begin 65 | Path := GetComponent as TPath; 66 | TTextPathEditor.Edit(Path); 67 | end; 68 | 69 | function TPathEditor.GetVerb(Index: Integer): string; 70 | begin 71 | Result := 'TextPath ...'; 72 | end; 73 | 74 | function TPathEditor.GetVerbCount: Integer; 75 | begin 76 | Result := 1; 77 | end; 78 | 79 | { TTextPathEditor } 80 | 81 | class procedure TTextPathEditor.Edit(APath: TPath); 82 | var 83 | Editor: TTextPathEditor; 84 | begin 85 | Editor := TTextPathEditor.Create(nil); 86 | try 87 | if Editor.ShowModal() = mrOK then 88 | begin 89 | APath.Data.Assign(Editor.Path.Data); 90 | end; 91 | finally 92 | Editor.Free; 93 | end; 94 | end; 95 | 96 | procedure TTextPathEditor.edTextChange(Sender: TObject); 97 | var 98 | Size : Integer; 99 | Style: TFontStyles; 100 | begin 101 | if lbFonts.ItemIndex >= 0 then 102 | begin 103 | Size := StrToInt(edSize.Text); 104 | Style := []; 105 | if cbBold.IsChecked then 106 | Style := [TFontStyle.fsBold]; 107 | if cbItalic.IsChecked then 108 | Style := Style + [TFontStyle.fsItalic]; 109 | BuildText(edText.Text, lbFonts.Items[lbFonts.ItemIndex], Size, Style, Path.Data); 110 | end; 111 | end; 112 | 113 | procedure TTextPathEditor.FormCreate(Sender: TObject); 114 | begin 115 | GetFontList(lbFonts.Items); 116 | lbFonts.ItemIndex := 0; 117 | end; 118 | 119 | end. 120 | -------------------------------------------------------------------------------- /TextPath/Execute.FMX.TextPathDesigner.dpk: -------------------------------------------------------------------------------- 1 | package Execute.FMX.TextPathDesigner; 2 | 3 | { 4 | (c)2017 Execute SARL 5 | } 6 | 7 | {$R *.res} 8 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 9 | {$ALIGN 8} 10 | {$ASSERTIONS ON} 11 | {$BOOLEVAL OFF} 12 | {$DEBUGINFO OFF} 13 | {$EXTENDEDSYNTAX ON} 14 | {$IMPORTEDDATA ON} 15 | {$IOCHECKS ON} 16 | {$LOCALSYMBOLS ON} 17 | {$LONGSTRINGS ON} 18 | {$OPENSTRINGS ON} 19 | {$OPTIMIZATION OFF} 20 | {$OVERFLOWCHECKS OFF} 21 | {$RANGECHECKS OFF} 22 | {$REFERENCEINFO ON} 23 | {$SAFEDIVIDE OFF} 24 | {$STACKFRAMES ON} 25 | {$TYPEDADDRESS OFF} 26 | {$VARSTRINGCHECKS ON} 27 | {$WRITEABLECONST OFF} 28 | {$MINENUMSIZE 1} 29 | {$IMAGEBASE $400000} 30 | {$DEFINE DEBUG} 31 | {$ENDIF IMPLICITBUILDING} 32 | {$IMPLICITBUILD ON} 33 | 34 | requires 35 | rtl, 36 | DesignIDE, 37 | fmx; 38 | 39 | contains 40 | Execute.FMX.TextPath in 'Execute.FMX.TextPath.pas' {TextPathEditor}, 41 | Execute.FontBuilder in 'Execute.FontBuilder.pas'; 42 | 43 | end. 44 | -------------------------------------------------------------------------------- /TextPath/Execute.FMX.TextPathDesigner.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {44D81C8D-F975-4463-9001-8F0998AD9BED} 4 | Execute.FMX.TextPathDesigner.dpk 5 | 18.2 6 | FMX 7 | True 8 | Debug 9 | Win32 10 | 1 11 | Package 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Base 34 | true 35 | 36 | 37 | true 38 | Base 39 | true 40 | 41 | 42 | true 43 | Base 44 | true 45 | 46 | 47 | true 48 | Base 49 | true 50 | 51 | 52 | true 53 | Base 54 | true 55 | 56 | 57 | true 58 | Base 59 | true 60 | 61 | 62 | true 63 | Cfg_1 64 | true 65 | true 66 | 67 | 68 | true 69 | Base 70 | true 71 | 72 | 73 | .\$(Platform)\$(Config) 74 | .\$(Platform)\$(Config) 75 | false 76 | false 77 | false 78 | false 79 | false 80 | true 81 | true 82 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 83 | All 84 | Execute_FMX_TextPathDesigner 85 | 86 | 87 | None 88 | android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar 89 | rtl;fmx;$(DCC_UsePackage) 90 | 91 | 92 | None 93 | rtl;fmx;$(DCC_UsePackage) 94 | 95 | 96 | None 97 | rtl;fmx;$(DCC_UsePackage) 98 | 99 | 100 | None 101 | rtl;fmx;$(DCC_UsePackage) 102 | 103 | 104 | rtl;$(DCC_UsePackage) 105 | 106 | 107 | rtl;fmx;$(DCC_UsePackage) 108 | 109 | 110 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 111 | Debug 112 | true 113 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 114 | 1033 115 | rtl;fmx;Execute.FMX;$(DCC_UsePackage) 116 | 117 | 118 | rtl;fmx;$(DCC_UsePackage) 119 | 120 | 121 | DEBUG;$(DCC_Define) 122 | true 123 | false 124 | true 125 | true 126 | true 127 | 128 | 129 | false 130 | 131 | 132 | false 133 | RELEASE;$(DCC_Define) 134 | 0 135 | 0 136 | 137 | 138 | 139 | MainSource 140 | 141 | 142 | 143 | 144 | 145 | 146 |
TextPathEditor
147 |
148 | 149 | 150 | Cfg_2 151 | Base 152 | 153 | 154 | Base 155 | 156 | 157 | Cfg_1 158 | Base 159 | 160 |
161 | 162 | Delphi.Personality.12 163 | Package 164 | 165 | 166 | 167 | Execute.FMX.TextPathDesigner.dpk 168 | 169 | 170 | 171 | 172 | 173 | true 174 | 175 | 176 | 177 | 178 | true 179 | 180 | 181 | 182 | 183 | true 184 | 185 | 186 | 187 | 188 | true 189 | 190 | 191 | 192 | 193 | Execute_FMX_TextPathDesigner.bpl 194 | true 195 | 196 | 197 | 198 | 199 | 1 200 | 201 | 202 | Contents\MacOS 203 | 0 204 | 205 | 206 | 207 | 208 | classes 209 | 1 210 | 211 | 212 | 213 | 214 | library\lib\armeabi-v7a 215 | 1 216 | 217 | 218 | 219 | 220 | library\lib\armeabi 221 | 1 222 | 223 | 224 | 225 | 226 | library\lib\mips 227 | 1 228 | 229 | 230 | 231 | 232 | library\lib\armeabi-v7a 233 | 1 234 | 235 | 236 | 237 | 238 | res\drawable 239 | 1 240 | 241 | 242 | 243 | 244 | res\values 245 | 1 246 | 247 | 248 | 249 | 250 | res\drawable 251 | 1 252 | 253 | 254 | 255 | 256 | res\drawable-xxhdpi 257 | 1 258 | 259 | 260 | 261 | 262 | res\drawable-ldpi 263 | 1 264 | 265 | 266 | 267 | 268 | res\drawable-mdpi 269 | 1 270 | 271 | 272 | 273 | 274 | res\drawable-hdpi 275 | 1 276 | 277 | 278 | 279 | 280 | res\drawable-xhdpi 281 | 1 282 | 283 | 284 | 285 | 286 | res\drawable-small 287 | 1 288 | 289 | 290 | 291 | 292 | res\drawable-normal 293 | 1 294 | 295 | 296 | 297 | 298 | res\drawable-large 299 | 1 300 | 301 | 302 | 303 | 304 | res\drawable-xlarge 305 | 1 306 | 307 | 308 | 309 | 310 | 1 311 | 312 | 313 | 1 314 | 315 | 316 | 0 317 | 318 | 319 | 320 | 321 | 1 322 | .framework 323 | 324 | 325 | 0 326 | 327 | 328 | 329 | 330 | 1 331 | .dylib 332 | 333 | 334 | 0 335 | .dll;.bpl 336 | 337 | 338 | 339 | 340 | 1 341 | .dylib 342 | 343 | 344 | 1 345 | .dylib 346 | 347 | 348 | 1 349 | .dylib 350 | 351 | 352 | 1 353 | .dylib 354 | 355 | 356 | 0 357 | .bpl 358 | 359 | 360 | 361 | 362 | 0 363 | 364 | 365 | 0 366 | 367 | 368 | 0 369 | 370 | 371 | 0 372 | 373 | 374 | 0 375 | 376 | 377 | 0 378 | 379 | 380 | 381 | 382 | 1 383 | 384 | 385 | 1 386 | 387 | 388 | 1 389 | 390 | 391 | 392 | 393 | 1 394 | 395 | 396 | 1 397 | 398 | 399 | 1 400 | 401 | 402 | 403 | 404 | 1 405 | 406 | 407 | 1 408 | 409 | 410 | 1 411 | 412 | 413 | 414 | 415 | 1 416 | 417 | 418 | 1 419 | 420 | 421 | 1 422 | 423 | 424 | 425 | 426 | 1 427 | 428 | 429 | 1 430 | 431 | 432 | 1 433 | 434 | 435 | 436 | 437 | 1 438 | 439 | 440 | 1 441 | 442 | 443 | 1 444 | 445 | 446 | 447 | 448 | 1 449 | 450 | 451 | 1 452 | 453 | 454 | 1 455 | 456 | 457 | 458 | 459 | 1 460 | 461 | 462 | 463 | 464 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 465 | 1 466 | 467 | 468 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 469 | 1 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 1 478 | 479 | 480 | 1 481 | 482 | 483 | 1 484 | 485 | 486 | 487 | 488 | 489 | 490 | Contents\Resources 491 | 1 492 | 493 | 494 | 495 | 496 | library\lib\armeabi-v7a 497 | 1 498 | 499 | 500 | 1 501 | 502 | 503 | 1 504 | 505 | 506 | 1 507 | 508 | 509 | 1 510 | 511 | 512 | 1 513 | 514 | 515 | 0 516 | 517 | 518 | 519 | 520 | 1 521 | 522 | 523 | 1 524 | 525 | 526 | 527 | 528 | Assets 529 | 1 530 | 531 | 532 | Assets 533 | 1 534 | 535 | 536 | 537 | 538 | Assets 539 | 1 540 | 541 | 542 | Assets 543 | 1 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | False 557 | False 558 | False 559 | False 560 | False 561 | False 562 | True 563 | False 564 | 565 | 566 | 12 567 | 568 | 569 | 570 | 571 |
572 | -------------------------------------------------------------------------------- /TextPath/Execute.FontBuilder.pas: -------------------------------------------------------------------------------- 1 | unit Execute.FontBuilder; 2 | 3 | { 4 | Create a vectorial text in a FMX TPath (c)2017 Execute SARL 5 | http://www.execute.fr 6 | 7 | 8 | NB: this font builder works only under Windows, but the generated Path can be used on any plateform 9 | } 10 | 11 | interface 12 | 13 | uses 14 | System.Classes, 15 | System.UITypes, 16 | Fmx.Graphics; 17 | 18 | procedure GetFontList(List: TStrings); 19 | procedure BuildText(const Text, FontName: string; Size: Integer; Style: TFontStyles; Path: TPathData); 20 | 21 | implementation 22 | 23 | uses 24 | System.SysUtils, 25 | System.Types, 26 | Winapi.Windows; 27 | 28 | function FixToX(const AFix: TFixed): Double; 29 | begin 30 | Result := (AFix.fract/65536.0 + AFix.value); 31 | end; 32 | 33 | function FixToY(const AFix: TFixed): Double; 34 | begin 35 | Result := - (AFix.fract/65536.0 + AFix.value); 36 | end; 37 | 38 | procedure BuildGlyph(DC: HDC; var x, y: Single; Ch: Char; Path: TPathData; const TextMetric: TTextMetric); 39 | var 40 | Matrix : TMAT2; 41 | Size : Cardinal; 42 | Metrics: TGLYPHMETRICS; 43 | Buffer : TBytes; 44 | Index : Integer; 45 | Header : PTTPolygonHeader; 46 | p : TPointF; 47 | Len : Integer; 48 | Curve : PTTPolyCurve; 49 | Point : PPointfx; 50 | Count : Integer; 51 | c : TPointF; 52 | begin 53 | if Ch = ' ' then 54 | begin 55 | GetCharWidth(DC, 32 , 32, Len); 56 | x := x + Len; 57 | Exit; 58 | end; 59 | 60 | FillChar(Matrix, SizeOf(Matrix), 0); 61 | Matrix.eM11.Value := 1; 62 | Matrix.eM22.Value := 1; 63 | 64 | Size := GetGlyphOutline(DC, Ord(Ch), GGO_NATIVE, Metrics, 0, nil, Matrix); 65 | if (Size = 0) or (Size = GDI_ERROR) then 66 | Exit; 67 | 68 | SetLength(Buffer, Size); 69 | Size := GetGlyphOutline(DC, Ord(Ch), GGO_NATIVE, Metrics, Size, Buffer, Matrix); 70 | if (Size = 0) or (Size = GDI_ERROR) then 71 | Exit; 72 | 73 | Index := 0; 74 | while Index < Size do 75 | begin 76 | Header := @Buffer[Index]; 77 | if Header.dwType <> TT_POLYGON_TYPE then 78 | Exit; 79 | p.x := x + FixToX(Header.pfxStart.x); 80 | p.y := y + FixToY(Header.pfxStart.y); 81 | if Index > 0 then 82 | Path.ClosePath; 83 | Path.MoveTo(p); 84 | Len := Index + Header.cb; 85 | Inc(Index, SizeOf(TTPOLYGONHEADER)); 86 | while Index < Len do 87 | begin 88 | Curve := @Buffer[Index]; 89 | Point := @Curve.apfx; 90 | case Curve.wType of 91 | TT_PRIM_LINE: 92 | for Count := 1 to Curve.cpfx do 93 | begin 94 | p.X := x + FixToX(Point.x); 95 | p.Y := y + FixToY(Point.y); 96 | Inc(Point); 97 | Path.LineTo(P); 98 | end; 99 | TT_PRIM_QSPLINE: 100 | for Count := 1 to Curve.cpfx - 1 do 101 | begin 102 | p.X := x + FixToX(Point.x); 103 | p.Y := y + FixToY(Point.y); 104 | Inc(Point); 105 | c.X := x + FixToX(Point.x); 106 | c.Y := y + FixToY(Point.y); 107 | if Count < Curve.cpfx - 1 then 108 | begin 109 | c.x := (p.X + c.X) / 2; 110 | c.y := (p.Y + c.Y) / 2; 111 | end; 112 | Path.QuadCurveTo(p, c); 113 | end; 114 | else 115 | Exit; 116 | end; 117 | Inc(Index, SizeOf(TTPOLYCURVE) + Pred(Curve.cpfx) * SizeOf(TPOINTFX)); 118 | end; 119 | end; 120 | 121 | x := x + Metrics.gmCellIncX; 122 | y := y + Metrics.gmCellIncY; 123 | 124 | Path.ClosePath; 125 | end; 126 | 127 | procedure BuildText(const Text, FontName: string; Size: Integer; Style: TFontStyles; Path: TPathData); 128 | var 129 | LogFont : TLogFont; 130 | Font : HFont; 131 | DC : HDC; 132 | OldFont : HFont; 133 | TextMetric: TTextMetric; 134 | Index : Integer; 135 | x, y : Single; 136 | begin 137 | Path.Clear; 138 | FillChar(LogFont, SizeOf(LogFont), 0); 139 | LogFont.lfHeight := -Size; 140 | LogFont.lfCharSet := DEFAULT_CHARSET; 141 | if TFontStyle.fsBold in Style then 142 | LogFont.lfWeight := FW_BOLD 143 | else 144 | LogFont.lfWeight := FW_NORMAL; 145 | LogFont.lfItalic := Byte(TFontStyle.fsItalic in Style); 146 | StrPLCopy(LogFont.lfFaceName, UTF8ToString(FontName), Length(LogFont.lfFaceName) - 1); 147 | Font := CreateFontIndirect(LogFont); 148 | DC := CreateCompatibleDC(GetDC(0)); 149 | try 150 | OldFont := SelectObject(DC, Font); 151 | GetTextMetrics(DC, TextMetric); 152 | x := 0; 153 | y := 0; 154 | for Index := 1 to Length(Text) do 155 | begin 156 | BuildGlyph(DC, x, y, Text[Index], Path, TextMetric); 157 | end; 158 | SelectObject(DC, OldFont); 159 | 160 | DeleteObject(Font); 161 | finally 162 | DeleteDC(DC); 163 | end; 164 | end; 165 | 166 | function EnumFontsProc(var LogFont: TLogFont; var TextMetric: TTextMetric; 167 | FontType: Integer; Data: Pointer): Integer; stdcall; 168 | var 169 | S: TStrings; 170 | Temp: string; 171 | begin 172 | if FontType and TRUETYPE_FONTTYPE <> 0 then 173 | begin 174 | S := TStrings(Data); 175 | Temp := LogFont.lfFaceName; 176 | if (S.Count = 0) or (Temp <> S[S.Count-1]) then 177 | S.Add(Temp); 178 | end; 179 | Result := 1; 180 | end; 181 | 182 | procedure GetFontList(List: TStrings); 183 | var 184 | DC: HDC; 185 | LList: TStringList; 186 | LFont: TLogFont; 187 | begin 188 | DC := GetDC(0); 189 | FillChar(LFont, sizeof(LFont), 0); 190 | LFont.lfCharset := DEFAULT_CHARSET; 191 | LList := TStringList.Create; 192 | try 193 | LList.Sorted := True; 194 | EnumFontFamiliesEx(DC, LFont, @EnumFontsProc, Winapi.Windows.LPARAM(LList), 0); 195 | List.Assign(LList); 196 | finally 197 | LList.Free; 198 | end; 199 | ReleaseDC(0, DC); 200 | end; 201 | 202 | end. 203 | 204 | -------------------------------------------------------------------------------- /TextPath/TextPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/TextPath/TextPath.png -------------------------------------------------------------------------------- /TextPath/TextPath2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/TextPath/TextPath2.png -------------------------------------------------------------------------------- /TextPath/readme.md: -------------------------------------------------------------------------------- 1 | # TextPath 2 | 3 | Execute.FMX.TextPathDesigner is a Delphi package that add a "Text Path..." popup option to the FMX TPath component. 4 | 5 | This let you create a vectorial text for any plateform from the Windows True Type Fonts. 6 | 7 | ![screenshot](TextPath.png) 8 | 9 | Fill free to add FMX Effects :) 10 | 11 | ![screenshot](TextPath2.png) 12 | -------------------------------------------------------------------------------- /WoodTexture/NathaanTFM.AS3Perlin.pas: -------------------------------------------------------------------------------- 1 | unit NathaanTFM.AS3Perlin; 2 | 3 | // Delphi translation of https://github.com/NathaanTFM/as3-perlin 4 | // (c)2024 Execute SARL 5 | 6 | interface 7 | {$POINTERMATH ON} 8 | {.$DEFINE OFFSETS} 9 | {$Q-} 10 | uses 11 | System.Math; 12 | 13 | type 14 | TPerlinVector2 = record 15 | x: Double; 16 | y: Double; 17 | end; 18 | PPerlinVector2 = ^TPerlinVector2; 19 | 20 | TAS3PerlinNoise = record 21 | private 22 | baseX: Double; 23 | baseY: Double; 24 | 25 | numOctaves: Cardinal; 26 | 27 | permutations: array[0..255] of Byte; 28 | vectors: array[0..3, 0..255] of TPerlinVector2; 29 | 30 | stitch: Boolean; 31 | stitchArr: array[0..1] of Cardinal; 32 | 33 | fractalNoise: Boolean; 34 | 35 | channelOptions: Byte; 36 | channelCount: Byte; 37 | grayScale: Boolean; 38 | 39 | {$IFDEF OFFSETS} 40 | offsets: TArray; 41 | {$ENDIF} 42 | procedure generateRandom(randomSeed: Integer); 43 | public 44 | constructor Create(Width, height: Integer; baseX, baseY: Double; numOctaves, randomSeed: Integer; stitch, fractalNoise: Boolean; channelOptions: Cardinal = 0; grayScale: Boolean = False; offsets: PPerlinVector2 = nil); 45 | function generatePerlinNoise(x, y: Integer): Cardinal; 46 | end; 47 | 48 | implementation 49 | 50 | const 51 | Epsilon = 0.001; 52 | 53 | function getNextRandomSeed(randomSeed: Integer): Integer; 54 | begin 55 | Result := -2836 * (randomSeed div 127773) + 16807 * (randomSeed mod 127773); 56 | if Result <= 0 then 57 | Inc(Result, $7FFFFFFF); // what if it's equals to -0x80000000?? 58 | end; 59 | 60 | function interpolate(a0, a1, w: Double): Double; inline; 61 | begin 62 | Result := (a1 - a0) * (3.0 - w * 2.0) * w * w + a0; 63 | end; 64 | 65 | function unmultiplyColor(red, green, blue, alpha: Byte): Cardinal; 66 | begin 67 | if alpha <> 255 then 68 | begin 69 | var val: Cardinal := 0; 70 | if alpha <> 0 then 71 | val := $FF00 div alpha; 72 | red := (val * red + $7F) shr 8; 73 | green := (val * green + $7F) shr 8; 74 | blue := (val * blue + $7F) shr 8; 75 | end; 76 | Result := (alpha shl 24) or (red shl 16) or (green shl 8) or blue; 77 | end; 78 | 79 | { TAS3PerlinNoise } 80 | 81 | constructor TAS3PerlinNoise.Create(Width, height: Integer; baseX, baseY: Double; numOctaves, 82 | randomSeed: Integer; stitch, fractalNoise: Boolean; channelOptions: Cardinal; 83 | grayScale: Boolean; offsets: PPerlinVector2); 84 | begin 85 | 86 | if Abs(baseX) > Epsilon then 87 | baseX := 1/Abs(baseX); 88 | 89 | if Abs(baseY) > Epsilon then 90 | baseY := 1/Abs(baseY); 91 | 92 | Self.numOctaves := numOctaves; 93 | 94 | generateRandom(randomSeed); 95 | 96 | Self.stitch := stitch; 97 | 98 | if stitch then 99 | begin 100 | if Abs(baseX) > Epsilon then 101 | begin 102 | var tmp1 := Floor(baseX * width) / width; 103 | var tmp2 := Ceil(baseX * width) / width; 104 | 105 | if (Abs(tmp1) < Epsilon) or (baseX / tmp1 >= tmp2 / baseX) then 106 | baseX := tmp2 107 | else 108 | baseX := tmp1; 109 | end; 110 | 111 | if Abs(baseY) > Epsilon then 112 | begin 113 | var tmp1 := Floor(baseY * height) / height; 114 | var tmp2 := Ceil(baseY * height) / height; 115 | 116 | if (Abs(tmp1) < Epsilon) or (baseX / tmp1 >= tmp2 / baseX) then 117 | baseY := tmp2 118 | else 119 | baseY := tmp1; 120 | end; 121 | 122 | stitchArr[0] := Round(Width * baseX); 123 | stitchArr[1] := Round(height * baseY); 124 | end; 125 | 126 | Self.baseX := baseX; 127 | Self.baseY := baseY; 128 | Self.fractalNoise := fractalNoise; 129 | 130 | Self.channelOptions := channelOptions; 131 | Self.grayScale := grayScale; 132 | 133 | if grayScale then 134 | channelCount := 1 135 | else 136 | channelCount := Ord(channelOptions and 1 <> 0) + Ord(channelOptions and 2 <> 0) + Ord(channelOptions and 4 <> 0); 137 | 138 | Inc(channelCount, Ord(channelOptions and 8 <> 0)); 139 | 140 | {$IFDEF OFFSETS} 141 | SetLength(Self.offsets, numOctaves); 142 | 143 | if offsets <> nil then 144 | Move(offsets^, Self.offsets[0], numOctaves * SizeOf(TPerlinVector2)); 145 | {$ENDIF} 146 | end; 147 | 148 | procedure TAS3PerlinNoise.generateRandom(randomSeed: Integer); 149 | begin 150 | if randomSeed <= 0 then 151 | randomSeed := Abs(randomSeed - 1) 152 | else 153 | if randomSeed = $7FFFFFFF then 154 | Dec(randomSeed); 155 | 156 | for var i := 0 to 3 do 157 | begin 158 | for var j := 0 to 255 do 159 | begin 160 | var vector: PPerlinVector2 := @vectors[i, j]; 161 | 162 | randomSeed := getNextRandomSeed(randomSeed); 163 | vector.x := (randomSeed mod 512 - 256) / 256.0; 164 | 165 | randomSeed := getNextRandomSeed(randomSeed); 166 | vector.y := (randomSeed mod 512 - 256) / 256.0; 167 | 168 | var dist := sqrt(Power(vector.x, 2) + Power(vector.y, 2)); 169 | 170 | if dist < Epsilon then 171 | begin 172 | vector.x := 0; 173 | vector.y := 0; 174 | end else begin 175 | vector.x := vector.x / dist; 176 | vector.y := vector.y / dist; 177 | end; 178 | end; 179 | end; 180 | 181 | for var i := 0 to 255 do 182 | permutations[i] := i; 183 | 184 | for var i := 255 downto 1 do 185 | begin 186 | randomSeed := getNextRandomSeed(randomSeed); 187 | 188 | var j := randomSeed and $FF; 189 | var temp := permutations[j]; 190 | permutations[j] := permutations[i]; 191 | permutations[i] := temp; 192 | end; 193 | end; 194 | 195 | 196 | function TAS3PerlinNoise.generatePerlinNoise(x, y: Integer): Cardinal; 197 | var 198 | red, green, blue, alpha: Cardinal; 199 | channelAlpha: Double; 200 | channels: array[0..3] of Double; 201 | begin 202 | red := 0; green := 0; blue := 0; alpha := 255; 203 | 204 | var baseX := Self.baseX; 205 | var baseY := Self.baseY; 206 | 207 | channelAlpha := 255; 208 | 209 | FillChar(channels, SizeOf(channels), 0); 210 | 211 | for var octave := 0 to numOctaves - 1 do 212 | begin 213 | var offsetX := ({$IFDEF OFFSETS}offsets[octave].x +{$ENDIF} x) * baseX + 4096.0; 214 | var offsetY := ({$IFDEF OFFSETS}offsets[octave].y +{$ENDIF} y) * baseY + 4096.0; 215 | 216 | var x0 := Floor(offsetX); 217 | var x1 := x0 + 1; 218 | 219 | var y0 := Floor(offsetY); 220 | var y1 := y0 + 1; 221 | 222 | var dx0 := offsetX - x0; // Floor(offsetX); 223 | var dx1 := dx0 - 1.0; 224 | 225 | var dy0 := offsetY - y0; // Floor(offsetY); 226 | var dy1 := dy0 - 1.0; 227 | 228 | if stitch then 229 | begin 230 | var tmp1 := stitchArr[0] + 4096; 231 | var tmp2 := stitchArr[1] + 4096; 232 | 233 | if x0 >= tmp1 then 234 | x0 := x0 - stitchArr[0]; 235 | 236 | if x1 >= tmp1 then 237 | x1 := x1 - stitchArr[0]; 238 | 239 | if y0 >= tmp2 then 240 | y0 := y0 - stitchArr[1]; 241 | 242 | if y1 >= tmp2 then 243 | y1 := y1 - stitchArr[1]; 244 | end; 245 | 246 | var idx1 := permutations[x0 and 255]; 247 | var idx2 := permutations[x1 and 255]; 248 | 249 | var v1 := permutations[(y0 + idx1) and 255]; 250 | var v2 := permutations[(y0 + idx2) and 255]; 251 | var v3 := permutations[(y1 + idx1) and 255]; 252 | var v4 := permutations[(y1 + idx2) and 255]; 253 | 254 | for var channel := 0 to channelCount - 1 do 255 | begin 256 | var n0, n1: Double; 257 | var vectorArray: PPerlinVector2 := @vectors[channel]; 258 | 259 | n0 := vectorArray[v1].x * dx0 + vectorArray[v1].y * dy0; 260 | n1 := vectorArray[v2].x * dx1 + vectorArray[v2].y * dy0; 261 | var ix1 := interpolate(n0, n1, dx0); 262 | 263 | n0 := vectorArray[v3].x * dx0 + vectorArray[v3].y * dy1; 264 | n1 := vectorArray[v4].x * dx1 + vectorArray[v4].y * dy1; 265 | var ix2 := interpolate(n0, n1, dx0); 266 | 267 | var value := interpolate(ix1, ix2, dy0); 268 | if fractalNoise then 269 | channels[channel] := channels[channel] + value * channelAlpha 270 | else 271 | channels[channel] := channels[channel] + Abs(value) * channelAlpha 272 | end; 273 | 274 | channelAlpha := channelAlpha * 0.5; 275 | baseX := baseX * 2.0; 276 | baseY := baseY * 2.0; 277 | 278 | if stitch then 279 | begin 280 | stitchArr[0] := stitchArr[0] * 2; 281 | stitchArr[1] := stitchArr[1] * 2; 282 | end; 283 | end; 284 | 285 | var nextChannel := 0; 286 | if fractalNoise then 287 | begin 288 | if grayScale then 289 | begin 290 | red := Cardinal(Round(channels[nextChannel] + 255.0) shr 1); Inc(nextChannel); 291 | green := red; 292 | blue := red; 293 | end else begin 294 | if channelOptions and 1 <> 0 then begin red := Cardinal(round(channels[nextChannel] + 255.0) shr 1); Inc(nextChannel); end; 295 | if channelOptions and 2 <> 0 then begin green := Cardinal(round(channels[nextChannel] + 255.0) shr 1); Inc(nextChannel); end; 296 | if channelOptions and 4 <> 0 then begin blue := Cardinal(round(channels[nextChannel] + 255.0) shr 1); Inc(nextChannel); end; 297 | end; 298 | if channelOptions and 8 <> 0 then alpha := round(channels[nextChannel] + 255.0) shr 1; 299 | end else begin 300 | if grayScale then 301 | begin 302 | red := round(channels[nextChannel]); Inc(nextChannel); 303 | green := red; 304 | blue := red; 305 | end else begin 306 | if channelOptions and 1 <> 0 then begin red := round(channels[nextChannel]); Inc(nextChannel); end; 307 | if channelOptions and 2 <> 0 then begin green := round(channels[nextChannel]); Inc(nextChannel); end; 308 | if channelOptions and 4 <> 0 then begin blue := round(channels[nextChannel]); Inc(nextChannel); end; 309 | end; 310 | if channelOptions and 8 <> 0 then alpha := round(channels[nextChannel]); 311 | end; 312 | 313 | alpha := Min(Max(alpha, 0), 255); 314 | red := Min(Max(red, 0), alpha); 315 | green := Min(Max(green, 0), alpha); 316 | blue := Min(Max(blue, 0), alpha); 317 | 318 | Result := unmultiplyColor(red, green, blue, alpha); 319 | end; 320 | 321 | end. 322 | -------------------------------------------------------------------------------- /WoodTexture/Wood.FlashLike.pas: -------------------------------------------------------------------------------- 1 | unit Wood.FlashLike; 2 | 3 | { 4 | Delphi implementation of some of Flash (AS3) function (c) 2024 Execute SARL 5 | 6 | } 7 | 8 | interface 9 | {$POINTERMATH ON} 10 | uses 11 | System.Types, 12 | System.UITypes, 13 | System.Math, 14 | FMX.Types, 15 | FMX.Surfaces, 16 | NathaanTFM.AS3Perlin; 17 | 18 | type 19 | Number = Integer; 20 | 21 | BitmapData = class; 22 | 23 | BitmapFilter = interface 24 | procedure Filter(source: BitmapData; x, y: Integer; var pixel: Cardinal); 25 | end; 26 | 27 | BitmapData = class(TBitmapSurface) 28 | constructor Create(w, h: Integer); 29 | procedure perlinNoise(baseX, baseY: Double; numOctaves, randomSeed: Number; stitch, fractalNoise: Boolean; channelOptions: Number = 0; grayScale: Boolean = False; offsets: Pointer = nil); 30 | function Clone: BitmapData; 31 | function rectangle: TRect; 32 | procedure applyFilter(sourceBitmapData: BitmapData; const sourceRec: TRect; const destPoint: TPoint; filter: BitmapFilter); 33 | procedure fillRect(const R: TRect; color: Cardinal); 34 | procedure merge(sourceBitmapData: BitmapData; const sourceRect: TRect; const destPoint: TPoint; redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier: Integer); 35 | end; 36 | 37 | TDisplacementMapFilterMode = (clamp, color, ignore, wrap); 38 | 39 | DisplacementMapFilter = class(TInterfacedObject, BitmapFilter) 40 | protected 41 | mapBitmap: BitmapData; 42 | mapPoint: TPoint; 43 | componentX, componentY: Integer; 44 | scaleX, scaleY: Double; 45 | mode: TDisplacementMapFilterMode; 46 | color: Cardinal; 47 | alpha: Double; 48 | procedure Filter(source: BitmapData; x, y: Integer; var pixel: Cardinal); 49 | function getColor(x, y: Integer; source: BitmapData): Cardinal; 50 | public 51 | constructor Create(mapBitmap: BitmapData; mapPoint: TPoint; componentX, componentY: Integer; scaleX, scaleY: Double; mode: string = 'wrap'; color: Cardinal = 0; alpha: Double = 0); 52 | end; 53 | 54 | ColorMatrixFilter = class(TInterfacedObject, BitmapFilter) 55 | private 56 | Matrix: TArray; 57 | procedure Filter(source: BitmapData; x, y: Integer; var pixel: Cardinal); 58 | public 59 | constructor Create(const Matrix: TArray); 60 | end; 61 | 62 | ConvolutionFilter = class(TInterfacedObject, BitmapFilter) 63 | private 64 | MatrixX: Integer; 65 | MatrixY: Integer; 66 | Matrix: TArray; 67 | Bias: Integer; 68 | procedure Filter(source: BitmapData; x, y: Integer; var pixel: Cardinal); 69 | public 70 | constructor Create(MatrixX, MatrixY: Integer; const Matrix: TArray; Bias: Integer); 71 | end; 72 | 73 | type 74 | Rectangle = class 75 | class function Create(l, t, w, h: Integer): TRect; 76 | end; 77 | 78 | implementation 79 | 80 | function clampByte(color: Single): Byte; 81 | begin 82 | Result := Round(Min(Max(0, color), 255)); 83 | end; 84 | 85 | { Rectangle } 86 | 87 | class function Rectangle.Create(l: Integer; t: Integer; w: Integer; h: Integer): TRect; 88 | begin 89 | Result.Left := l; 90 | Result.Top := t; 91 | Result.Width := w - 1; 92 | Result.Height := h - 1; 93 | end; 94 | 95 | { BitmapData } 96 | 97 | procedure BitmapData.applyFilter(sourceBitmapData: BitmapData; 98 | const sourceRec: TRect; const destPoint: TPoint; filter: BitmapFilter); 99 | begin 100 | var source := sourceBitmapData; 101 | if source = Self then 102 | source := Clone(); 103 | var x1 := Min(Max(0, destPoint.X), Width); 104 | var X2 := Min(Max(0, destPoint.X + sourceRec.Width), Width); 105 | var y1 := Min(Max(0, destPoint.Y), Height); 106 | var y2 := Min(Max(0, destPoint.Y + sourcerec.Height), Height); 107 | var dx := x2 - x1 - 1; 108 | var dy := y2 - y1 - 1; 109 | 110 | for var y := 0 to dy do 111 | begin 112 | var p: PCardinal := ScanLine[y1 + y]; 113 | for var x := 0 to dx do 114 | begin 115 | filter.Filter(source, x + sourceRec.Left, y + sourceRec.Top, p[x1 + x]); 116 | end; 117 | end; 118 | if source <> sourceBitmapData then 119 | source.Free; 120 | end; 121 | 122 | function BitmapData.Clone: BitmapData; 123 | begin 124 | Result := BitmapData.Create(Width, Height); 125 | Result.Assign(Self); 126 | end; 127 | 128 | constructor BitmapData.Create(w, h: Integer); 129 | begin 130 | inherited Create; 131 | SetSize(w, h, TPixelFormat.BGRA); 132 | FillRect(TRect.Create(0, 0, w, h), $ff000000); 133 | end; 134 | 135 | procedure BitmapData.fillRect(const R: TRect; color: Cardinal); 136 | begin 137 | var x1 := Min(Max(0, R.Left), Width - 1); 138 | var x2 := Min(Max(0, R.Right), Width - 1); 139 | var y1 := Min(Max(0, R.Top), Height - 1); 140 | var y2 := Min(Max(0, R.Bottom), Height - 1); 141 | for var y := y1 to y2 do 142 | begin 143 | var p: PCardinal := ScanLine[y]; 144 | for var x := x1 to x2 do 145 | begin 146 | p[x] := color; 147 | end; 148 | end; 149 | 150 | end; 151 | 152 | procedure BitmapData.merge(sourceBitmapData: BitmapData; 153 | const sourceRect: TRect; const destPoint: TPoint; redMultiplier, 154 | greenMultiplier, blueMultiplier, alphaMultiplier: Integer); 155 | begin 156 | var x1 := Min(Max(0, destPoint.X), Width - 1); 157 | var x2 := Min(Max(0, destPoint.X + sourceRect.Width), Width - 1); 158 | var y1 := Min(Max(0, destPoint.Y), Height - 1); 159 | var y2 := Min(Max(0, destPoint.Y + sourceRect.Height), Height - 1); 160 | var dx := x2 - x1 - 1; 161 | var dy := y2 - y1 - 1; 162 | for var y := 0 to dy do 163 | begin 164 | var sy := sourceRect.Top + y; 165 | if sy < 0 then 166 | Continue; 167 | if sy > sourceBitmapData.Height then 168 | Exit; 169 | var P: PColorRec := ScanLine[y1 + y]; 170 | var S: PColorRec := sourceBitmapData.ScanLine[sy]; 171 | for var x := 0 to dx do 172 | begin 173 | var sx := sourceRect.Left + x; 174 | if sx < 0 then 175 | Continue; 176 | if sx > sourceBitmapData.Width then 177 | break; 178 | var PC: PColorRec := @P[x1 + x]; 179 | var PS: PColorRec := @S[sx]; 180 | PC.B := ClampByte(((PS.B * blueMultiplier) + (PC.B * (256 - blueMultiplier))) / 256); 181 | PC.G := ClampByte(((PS.G * greenMultiplier) + (PC.G * (256 - greenMultiplier))) / 256); 182 | PC.R := ClampByte(((PS.R * redMultiplier) + (PC.R * (256 - redMultiplier))) / 256); 183 | PC.A := ClampByte(((PS.A * alphaMultiplier) + (PC.A * (256 - alphaMultiplier))) / 256); 184 | end; 185 | end; 186 | end; 187 | 188 | procedure BitmapData.perlinNoise(baseX, baseY: Double; numOctaves, randomSeed: Number; stitch, fractalNoise: Boolean; channelOptions: Number = 0; grayScale: Boolean = False; offsets: Pointer = nil); 189 | var 190 | v: Cardinal; 191 | begin 192 | var perlin := TAS3PerlinNoise.Create(Width, Height, baseX, baseY, numOctaves, randomSeed, stitch, fractalNoise, channelOptions, grayScale, offsets); 193 | for var y := 0 to Height - 1 do 194 | begin 195 | var p: PCardinal := ScanLine[y]; 196 | for var x := 0 to Width - 1 do 197 | begin 198 | p[x]:= perlin.generatePerlinNoise(x, y); 199 | end; 200 | end; 201 | 202 | end; 203 | 204 | function BitmapData.rectangle: TRect; 205 | begin 206 | Result.Left := 0; 207 | Result.Top := 0; 208 | Result.Width := Width; 209 | Result.Height := Height; 210 | end; 211 | 212 | { DisplacementMapFilter } 213 | 214 | function getComponent(component: Integer; color: Cardinal): Integer; 215 | begin 216 | case component of 217 | 1: // RED 218 | Result := color and $FF; 219 | 2: // GREEN 220 | Result := (color shr 8) and $FF; 221 | 4: // BLUE 222 | Result := (color shr 16) and $FF; 223 | 8: // ALPHA 224 | Result := (color shr 24); 225 | end; 226 | end; 227 | 228 | procedure WrapValue(var x: Integer; max: Integer); 229 | begin 230 | while x < 0 do Inc(x, max); 231 | while x >= max do Dec(x, max); 232 | end; 233 | 234 | constructor DisplacementMapFilter.Create(mapBitmap: BitmapData; 235 | mapPoint: TPoint; componentX, componentY: Integer; scaleX, scaleY: Double; 236 | mode: string; color: Cardinal; alpha: Double); 237 | begin 238 | Self.mapBitmap := mapBitmap; 239 | Self.mapPoint := mapPoint; 240 | Self.componentX := componentX; 241 | Self.componentY := componentY; 242 | Self.scaleX := ScaleX; 243 | Self.scaleY := scaleY; 244 | if mode = 'clamp' then 245 | Self.mode := TDisplacementMapFilterMode.clamp 246 | else 247 | if mode = 'color' then 248 | Self.mode := TDisplacementMapFilterMode.color 249 | else 250 | if mode = 'ignore' then 251 | Self.mode := TDisplacementMapFilterMode.ignore 252 | else 253 | Self.mode := TDisplacementMapFilterMode.wrap; 254 | Self.color := color; 255 | Self.alpha := alpha; 256 | end; 257 | 258 | procedure DisplacementMapFilter.Filter(source: BitmapData; x, y: Integer; var pixel: Cardinal); 259 | begin 260 | // dstPixel[x, y] = srcPixel[x + ((componentX(x, y) - 128) * scaleX) / 256, y + ((componentY(x, y) - 128) *scaleY) / 256) 261 | if (x < 0) 262 | or (y < 0) 263 | or (x >= mapBitmap.Width) 264 | or (y >= mapBitmap.Height) then 265 | begin 266 | Exit; 267 | end; 268 | 269 | var l: PCardinal := mapBitmap.ScanLine[y]; 270 | var c := l[x]; 271 | 272 | {$IFDEF NO_SMOOTH} 273 | var sx: Integer := x + Round(((getComponent(componentX, c) - 128) * scaleX) / 256); 274 | var sy: Integer := y + Round(((getComponent(componentY, c) - 128) * scaleY) / 256); 275 | 276 | Pixel := getColor(sx, sy, source); 277 | {$ELSE} 278 | // I've tried to implement a smoothing but the result is poor 279 | 280 | var sx: Double := x + ((getComponent(componentX, c) - 128) * scaleX) / 256; 281 | var sy: Double := y + ((getComponent(componentY, c) - 128) * scaleY) / 256; 282 | 283 | var tx: Integer := Round(sx); 284 | var ty: Integer := Round(sy); 285 | 286 | var fx := sx - tx; 287 | var fy := sy - ty; 288 | 289 | var c1 := getColor(tx, ty, source); 290 | var c2 := getColor(tx + 1, ty, source); 291 | var c3 := getColor(tx, ty + 1, source); 292 | var c4 := getColor(tx + 1, ty + 1, source); 293 | 294 | var f2 := 1 - fx; 295 | 296 | var r1 := TColorRec(c1).R * f2 + TColorRec(c2).R * fx; 297 | var g1 := TColorRec(c1).G * f2 + TColorRec(c2).G * fx; 298 | var b1 := TColorRec(c1).B * f2 + TColorRec(c2).B * fx; 299 | var a1 := TColorRec(c1).A * f2 + TColorRec(c2).A * fx; 300 | 301 | var r2 := TColorRec(c3).R * f2 + TColorRec(c4).R * fx; 302 | var g2 := TColorRec(c3).G * f2 + TColorRec(c4).G * fx; 303 | var b2 := TColorRec(c3).B * f2 + TColorRec(c4).B * fx; 304 | var a2 := TColorRec(c3).A * f2 + TColorRec(c4).A * fx; 305 | 306 | f2 := 1 - fy; 307 | 308 | with TColorRec(pixel) do 309 | begin 310 | R := ClampByte(r1 * f2 + r2 * fy); 311 | G := ClampByte(g1 * f2 + g2 * fy); 312 | B := ClampByte(b1 * f2 + b2 * fy); 313 | A := ClampByte(a1 * f2 + a2 * fy); 314 | end; 315 | {$ENDIF} 316 | end; 317 | 318 | function DisplacementMapFilter.getColor(x, y: Integer; source: BitmapData): Cardinal; 319 | begin 320 | var cx := Min(Max(0, x), source.Width - 1); 321 | var cy := Min(Max(0, y), source.Height - 1); 322 | var clamped := (cx <> x) or (cy <> y); 323 | if clamped then 324 | begin 325 | case Mode of 326 | TDisplacementMapFilterMode.clamp: 327 | begin 328 | x := cx; 329 | y := cy; 330 | end; 331 | TDisplacementMapFilterMode.color: 332 | begin 333 | Result := Color; 334 | Exit; 335 | end; 336 | TDisplacementMapFilterMode.ignore: 337 | begin 338 | Result := 0; // ? 339 | Exit; 340 | end; 341 | TDisplacementMapFilterMode.wrap: 342 | begin 343 | WrapValue(x, source.Width); 344 | WrapValue(y, source.Height); 345 | end; 346 | end; 347 | end; 348 | var L: PCardinal := source.ScanLine[y]; 349 | Result := L[x]; 350 | end; 351 | 352 | { ColorMatrixFilter } 353 | 354 | constructor ColorMatrixFilter.Create(const Matrix: TArray); 355 | begin 356 | Self.Matrix := Matrix; 357 | end; 358 | 359 | procedure ColorMatrixFilter.Filter(source: BitmapData; x, y: Integer; 360 | var pixel: Cardinal); 361 | begin 362 | if (x < 0) 363 | or (y < 0) 364 | or (x >= source.Width) 365 | or (y >= source.Height) then 366 | begin 367 | Exit; 368 | end; 369 | var l: PColorRec := source.ScanLine[y]; 370 | var c: TColorRec := l[x]; 371 | with TColorRec(pixel) do 372 | begin 373 | B := clampByte(c.R * Matrix[ 0] + c.G * Matrix[ 1] + c.B * Matrix[ 2] + c.A * Matrix[ 3] + Matrix[ 4]); 374 | G := clampByte(c.R * Matrix[ 5] + c.G * Matrix[ 6] + c.B * Matrix[ 7] + c.A * Matrix[ 8] + Matrix[ 9]); 375 | R := clampByte(c.R * Matrix[10] + c.G * Matrix[11] + c.B * Matrix[12] + c.A * Matrix[13] + Matrix[14]); 376 | A := clampByte(c.R * Matrix[15] + c.G * Matrix[16] + c.B * Matrix[17] + c.A * Matrix[18] + Matrix[19]); 377 | end; 378 | end; 379 | 380 | { ConvolutionFilter } 381 | 382 | constructor ConvolutionFilter.Create(MatrixX, MatrixY: Integer; const Matrix: TArray; Bias: Integer); 383 | begin 384 | Self.MatrixX := MatrixX; 385 | Self.MatrixY := MatrixY; 386 | Self.Matrix := Matrix; 387 | Self.Bias := Bias; 388 | end; 389 | 390 | procedure ConvolutionFilter.Filter(source: BitmapData; x, y: Integer; 391 | var pixel: Cardinal); 392 | var 393 | ar, ag, ab, aa: Single; 394 | sum: Single; 395 | begin 396 | ar := 0; 397 | ag := 0; 398 | ab := 0; 399 | aa := 0; 400 | sum := 0; 401 | var oy := y - MatrixY div 2; 402 | var m := 0; 403 | for var my := 0 to MatrixY - 1 do 404 | begin 405 | if oy >= source.Height then 406 | Break; 407 | if oy >= 0 then 408 | begin 409 | var P: PColorRec := source.ScanLine[oy]; 410 | var ox := x - MatrixX div 2; 411 | for var mx := 0 to MatrixX - 1 do 412 | begin 413 | if ox >= source.Width then 414 | Break; 415 | var f := Matrix[m]; 416 | if ox >= 0 then 417 | begin 418 | ar := ar + p[ox].R * f; 419 | ag := ag + p[ox].G * f; 420 | ab := ab + p[ox].B * f; 421 | aa := aa + p[ox].A * f; 422 | sum := sum + f; 423 | end; 424 | Inc(ox); 425 | Inc(m); 426 | end; 427 | end else begin 428 | Inc(m, MatrixX); 429 | end; 430 | Inc(oy); 431 | end; 432 | if sum = 0 then 433 | Exit; 434 | with TColorRec(pixel) do 435 | begin 436 | var f := 1/sum; 437 | R := ClampByte(ar * f + bias); // bias ?! 438 | G := ClampByte(ag * f + bias); 439 | B := ClampByte(ab * f + bias); 440 | A := ClampByte(aa * f + bias); 441 | end; 442 | end; 443 | 444 | end. 445 | -------------------------------------------------------------------------------- /WoodTexture/Wood.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/WoodTexture/Wood.gif -------------------------------------------------------------------------------- /WoodTexture/WoodTexture.Main.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/WoodTexture/WoodTexture.Main.pas -------------------------------------------------------------------------------- /WoodTexture/WoodTexture.dpr: -------------------------------------------------------------------------------- 1 | program WoodTexture; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | WoodTexture.Main in 'WoodTexture.Main.pas' {Main}, 7 | NathaanTFM.AS3Perlin in 'NathaanTFM.AS3Perlin.pas', 8 | Wood.FlashLike in 'Wood.FlashLike.pas'; 9 | 10 | {$R *.res} 11 | 12 | begin 13 | Application.Initialize; 14 | Application.CreateForm(TMain, Main); 15 | Application.Run; 16 | end. 17 | -------------------------------------------------------------------------------- /WoodTexture/WoodTexture.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tothpaul/Firemonkey/9b9fef14bc608da041e8b64abbb4adde561eec22/WoodTexture/WoodTexture.res -------------------------------------------------------------------------------- /WoodTexture/readme.md: -------------------------------------------------------------------------------- 1 | # Wood Texture 2 | 3 | This is a Delphi FMX version of my [FlashPascal](https://github.com/tothpaul/FlashPascal) Wood demo 4 | 5 | The purpose is to create a procedural texture that looks like wood planks 6 | 7 | the Wood.FlashLike implements some of the ActionScript BitmapData functions used on the original demo 8 | 9 | ![screenshot](Wood.gif) 10 | 11 | 12 | --------------------------------------------------------------------------------