demo.pas 10 KB

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