demo.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. unit demo;
  2. {$mode objfpc}{$H+}
  3. {$I zglCustomConfig.cfg}
  4. interface
  5. // RU: обратите внимание!!!
  6. // Проекты LCL имеют свои конфигурационные файлы "zgl_config.cfg". Лучше всего для каждого вашего проекта иметь свой
  7. // конфигурационный файл, это может решить многие проблемы, если вдруг вы будете вносить изменения в конфигурацию проекта
  8. // и, это отобразится на других ваших проектах использующих тот же конфигурационный файл.
  9. // EN: note!!!
  10. // LCL projects have their own configuration files "zgl_config.cfg". It's best to have a separate config file for each of
  11. // your projects, this can solve many problems if you suddenly make changes to the project config and it will show up on
  12. // your other projects using the same config file.
  13. uses
  14. Classes,
  15. SysUtils,
  16. Forms,
  17. Controls,
  18. Graphics,
  19. Dialogs,
  20. ExtCtrls,
  21. {$IFDEF LINUX}
  22. {$IFDEF LCLGTK2}
  23. GTK2, GDK2x, GTK2Proc,
  24. {$ENDIF}
  25. {$ENDIF}
  26. {$IFDEF USE_ZENGL_STATIC}
  27. zgl_application,
  28. zgl_window,
  29. zgl_screen,
  30. zgl_render_2d,
  31. zgl_joystick,
  32. zgl_mouse,
  33. zgl_fx,
  34. zgl_font,
  35. zgl_text,
  36. zgl_textures,
  37. zgl_textures_png,
  38. zgl_types,
  39. zgl_collision_2d,
  40. zgl_sprite_2d,
  41. // sound
  42. zgl_sound,
  43. zgl_sound_wav,
  44. zgl_sound_ogg,
  45. zgl_utils
  46. {$ELSE}
  47. zglHeader
  48. {$ENDIF}
  49. , LCLType;
  50. type
  51. { TForm1 }
  52. TForm1 = class(TForm)
  53. Timer1: TTimer;
  54. procedure FormActivate(Sender: TObject);
  55. procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  56. procedure FormCreate(Sender: TObject);
  57. procedure FormDeactivate(Sender: TObject);
  58. procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  59. procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
  60. Shift: TShiftState; X, Y: Integer);
  61. procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  62. procedure Timer1Timer(Sender: TObject);
  63. private
  64. public
  65. end;
  66. var
  67. Form1: TForm1;
  68. //-----------------------------------------
  69. dirRes : UTF8String;
  70. fntMain : Byte;
  71. MyIcon : array[ 0..1 ] of zglPTexture;
  72. sound, audio : zglPSound;
  73. audioPlay : Boolean = false;
  74. state : Integer;
  75. r : zglTRect2D;
  76. p : Integer;
  77. // добавляем номер звука, пока для одного звука
  78. IDSound: array[0..1] of Integer;
  79. joyCount : Integer;
  80. // для возможности изменения экрана
  81. ScreenWidth : integer = 800;
  82. ScreenHeight : integer = 600;
  83. //------------------------------------------
  84. implementation
  85. {$R *.lfm}
  86. // RU: Т.к. звуковая подсистема нацелена на 3D, для позиционирования звуков в 2D нужны некоторые ухищрения.
  87. // EN: Because sound subsystem using 3D, there is some tricky way to calculate sound position in 2D.
  88. function CalcX2D( const X : Single ) : Single;
  89. begin
  90. Result := ( X - ScreenWidth / 2 ) * ( 10 / ScreenHeight / 2 ); // сменил смещение по X и Y, теперь более явно можно
  91. end; // отдалить/приблизить звук
  92. function CalcY2D( const Y : Single ) : Single;
  93. begin
  94. Result := ( Y - ScreenWidth / 2 ) * ( 10 / ScreenHeight / 2 );
  95. end;
  96. procedure Draw;
  97. begin
  98. setFontTextScale(15, fntMain);
  99. text_Draw( fntMain, 0, 0, 'Escape - Exit' );
  100. // RU: Координаты мыши можно получить при помощи функций mouse_X и mouse_Y.
  101. // EN: Mouse coordinates can be got using functions mouse_X and mouse_Y.
  102. text_Draw( fntMain, 0, 18, 'Mouse X, Y: ' + u_IntToStr( mouseX ) + '; ' + u_IntToStr( mouseY ) );
  103. ssprite2d_Draw( MyIcon[ state ], ( ScreenWidth - 128 ) / 2, ( ScreenHeight - 128 ) / 2, 128, 128, 0 );
  104. text_Draw( fntMain, ScreenWidth / 2, ScreenHeight / 2 + 64, 'Skillet - Comatose - Whispers In The Dark', TEXT_HALIGN_CENTER );
  105. if col2d_PointInRect( mouseX, mouseY, r ) Then
  106. begin
  107. fx_SetBlendMode( FX_BLEND_ADD );
  108. ssprite2d_Draw(MyIcon[state], (ScreenWidth - 132) / 2, (ScreenHeight - 132) / 2, 132, 132, 0, 155);
  109. fx_SetBlendMode( FX_BLEND_NORMAL );
  110. end;
  111. Application.ProcessMessages;
  112. end;
  113. procedure Init;
  114. begin
  115. wnd_SetSize( Form1.ClientWidth, Form1.ClientHeight );
  116. scrVSync := true;
  117. // RU: Инициализируем звуковую подсистему. Для Windows можно сделать выбор между DirectSound и OpenAL отредактировав файл zgl_config.cfg.
  118. // EN: Initializing sound subsystem. For Windows can be used DirectSound or OpenAL, see zgl_config.cfg.
  119. snd_Init();
  120. // RU: Загружаем звуковой файл и устанавливаем для него максимальноe количество проигрываемых источников в 2.
  121. // EN: Load the sound file and set maximum count of sources that can be played to 2.
  122. // RU: Инициализируем обработку ввода джойстиков и получаем количество подключенных джойстиков.
  123. // EN: Initialize processing joystick input and get count of plugged joysticks.
  124. joyCount := joy_Init();
  125. // RU: Загружаем текстуры, которые будут индикаторами.
  126. // EN: Load the textures, that will be indicators.
  127. MyIcon[ 0 ] := tex_LoadFromFile( dirRes + 'audio-stop.png' );
  128. MyIcon[ 1 ] := tex_LoadFromFile( dirRes + 'audio-play.png' );
  129. fntMain := font_LoadFromFile( dirRes + 'font.zfi' );
  130. sound := snd_LoadFromFile( dirRes + 'click.wav', 2 );
  131. audio := snd_LoadFromFile(dirRes + 'music.ogg', 2);
  132. end;
  133. { TForm1 }
  134. procedure TForm1.FormCreate(Sender: TObject);
  135. begin
  136. // RU: вариант для неизменного окна или выбирайте нужный вариант в настройках формы.
  137. // EN: option for a fixed window or select the desired option in the form settings.
  138. // Form1.BorderStyle := bsSingle;
  139. end;
  140. procedure TForm1.FormDeactivate(Sender: TObject);
  141. begin
  142. Timer1.Enabled := false;
  143. end;
  144. // закрываем форму
  145. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  146. begin
  147. Timer1.Enabled := false;
  148. zgl_Destroy;
  149. Application.Terminate;
  150. end;
  151. procedure TForm1.FormActivate(Sender: TObject);
  152. {$IFDEF LINUX}
  153. var
  154. widget : PGtkWidget;
  155. {$ENDIF}
  156. begin
  157. // Производим инициализацию --------------------------------------------------
  158. // RU: Вертикальная синхронизация поможет избежать загрузки процессора.
  159. // EN: Vertical synchronization will decrease a CPU loading.
  160. scrVSync := true;
  161. // RU: Перед стартом необходимо настроить viewport.
  162. // EN: Before the start need to configure a viewport.
  163. wnd_SetPos( Form1.Left, Form1.Top );
  164. // wnd_SetSize( Form1.ClientWidth, Form1.ClientHeight );
  165. Form1.BringToFront();
  166. r.X := ( Form1.ClientWidth - 128 ) / 2;
  167. r.Y := ( Form1.ClientHeight - 128 ) / 2;
  168. r.W := 128;
  169. r.H := 128;
  170. //-----------------------------------------------------
  171. zgl_Reg(SYS_LOAD, @Init);
  172. zgl_Reg( SYS_DRAW, @Draw );
  173. {$IFDEF LINUX}
  174. {$IFDEF LCLGTK2}
  175. widget := GetFixedWidget( PGtkWidget( Handle ) );
  176. gtk_widget_realize( widget );
  177. if not zgl_InitToHandle( GDK_WINDOW_XID( widget^.window ) ) then
  178. begin
  179. zgl_Destroy;
  180. Application.Terminate;
  181. Exit;
  182. end;
  183. {$ENDIF}
  184. {$ENDIF}
  185. {$IFDEF WINDOWS}
  186. if not zgl_InitToHandle( Handle ) then
  187. begin
  188. zgl_Destroy;
  189. Application.Terminate;
  190. Exit;
  191. end;
  192. {$ENDIF}
  193. // RU: таймер должен быть изначально выключен! Включаем таймер только когда окно инициализировано.
  194. // EN: the timer must be initially turned off! We turn on the timer only when the window is initialized.
  195. Timer1.Enabled := True;
  196. end;
  197. // RU: проверка нажатия клавиши.
  198. // EN: keypress check.
  199. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  200. begin
  201. if Key = 27 then
  202. Form1.Close;
  203. end;
  204. // RU: обработка мыши и проигрывание музыки.
  205. // EN: mouse handling and music playback.
  206. procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  207. Shift: TShiftState; X, Y: Integer);
  208. begin
  209. Timer1.Enabled := false;
  210. if Button = mbLeft then
  211. begin
  212. // RU: В данном случаи мы начинаем воспроизводить звук сразу в указанных координатах, но их можно менять и в процессе используя процедуру snd_SetPos.
  213. // Важно: Для OpenAL можно позиционировать только mono-звуки
  214. //
  215. // EN: In this case, we begin to play the sound directly in these coordinates, but they can be changed later using procedure snd_SetPos.
  216. // Important: OpenAL can position only mono-sounds.
  217. // !!! -------------------------------------------------------------------------
  218. // RU: эта часть изменена!!! Теперь можно заново воспроизводить звуки, даже если они не закончили играть.
  219. // EN: this part has changed! Sounds can now be replayed even if they haven't finished playing.
  220. if snd_Get(sound, IDSound[0], SND_STATE_PLAYING) = IDSound[0] then
  221. snd_Stop(sound, IDSound[0]);
  222. IDSound[0] := snd_Play(sound, FALSE, CalcX2D(X), CalcY2D(Y));
  223. // !!! -------------------------------------------------------------------------
  224. // RU: добавляем проверку на проигрывание звука, только если много разных звуков/музыки, то номера надо менять (не только 1!!!)
  225. // EN: we add a check for sound playback, only if there are many different sounds / music, then the numbers must be changed (not only 1 !!!)
  226. if col2d_PointInRect(X, Y, r) Then
  227. begin
  228. if audioPlay then
  229. snd_Stop(audio, IDSound[1])
  230. else
  231. IDSound[1] := snd_Play(audio, False);
  232. audioPlay := not audioPlay;
  233. end;
  234. end;
  235. Timer1.Enabled := true;
  236. end;
  237. // RU: для примера использования перемещения мышки.
  238. // EN: for an example of using mouse movement.
  239. procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  240. Y: Integer);
  241. begin
  242. Timer1.Enabled := False;
  243. mouseX := X;
  244. mouseY := Y;
  245. Timer1.Enabled := True;
  246. end;
  247. procedure TForm1.Timer1Timer(Sender: TObject);
  248. begin
  249. Timer1.Enabled := False;
  250. app_PLoop;
  251. // RU: Проверяем играет ли музыка(1 - играет, 0 - не играет). Так же можно проверить и звуки - подставив zglPSound и ID вот так:
  252. // snd_Get( Sound, ID...
  253. // ID возвращается функцией snd_Play
  254. //
  255. // EN: Check if music playing(1 - playing, 0 - not playing). Sounds also can be checked this way - just use zglPSound and ID:
  256. // snd_Get( Sound, ID...
  257. // ID returns by function snd_Play.
  258. state := snd_Get( audio, IDSound[1], SND_STATE_PLAYING );
  259. if state = 0 Then
  260. audioPlay := False;
  261. // RU: Получаем в процентах позицию проигрывания аудиопотока и ставим громкость для плавных переходов.
  262. // EN: Get position in percent's for audio stream and set volume for smooth playing.
  263. p := snd_Get( audio, IDSound[1], SND_STATE_PERCENT );
  264. if ( p >= 0 ) and ( p < 25 ) Then
  265. snd_SetVolume(audio, IDSound[1], ( 1 / 24 ) * p );
  266. if ( p >= 75 ) and ( p < 100 ) Then
  267. snd_SetVolume(audio, IDSound[1], 1 - ( 1 / 24 ) * ( p - 75 ) );
  268. Timer1.Enabled := True;
  269. end;
  270. end.