Compare commits

...
Author SHA1 Message Date
IgorA 1ed8821346 file panel data has been transferred to structures
Test PR / Build (en_US) (pull_request) Successful in 3m16s
Test PR / Build (es_ES) (pull_request) Successful in 3m19s
Test PR / Build (ru_RU) (pull_request) Successful in 3m23s
load icon indices from 'icon2ext.ini'
fix the menu's response to mouse clicks
2026-10-05 09:01:52 +03:00
IgorA 7c9ad9dde9 new icons
Test PR / Build (es_ES) (pull_request) Successful in 2m24s
Test PR / Build (en_US) (pull_request) Successful in 2m27s
Test PR / Build (ru_RU) (pull_request) Successful in 2m30s
2026-09-28 09:12:58 +03:00
IgorA c8cf7a834f small fixes
Test PR / Build (es_ES) (pull_request) Successful in 2m27s
Test PR / Build (ru_RU) (pull_request) Successful in 2m31s
Test PR / Build (en_US) (pull_request) Successful in 2m32s
2026-09-26 14:50:55 +03:00
IgorA 3b8dc9662d - fix in editbox (add lost variable mouse_flag)
Test PR / Build (en_US) (pull_request) Successful in 2m29s
Test PR / Build (es_ES) (pull_request) Successful in 2m14s
Test PR / Build (ru_RU) (pull_request) Successful in 2m21s
- add main menu (use klib.obj)
- add compile flag USE_STATIC_LIBS (for box_lib.obj)
2026-09-25 14:33:13 +03:00
IgorA a8412100b4 kfm:
Test PR / Build (es_ES) (pull_request) Successful in 2m29s
Test PR / Build (ru_RU) (pull_request) Successful in 2m34s
Test PR / Build (en_US) (pull_request) Successful in 2m41s
- system numbers have been replaced by constants
- replacement of the old function 64 with 68
- use the editbox, scrollbars from box_lib
- using sortlib
2026-09-22 11:32:35 +03:00
IgorA f711f9286b optimize import: (#689)
Build system / Build (es_ES) (push) Successful in 2m58s
Build system / Build (en_US) (push) Successful in 3m12s
Build system / Build (ru_RU) (push) Successful in 3m15s
Build system / Publish Images (push) Successful in 3m43s
color_dialog, fspeed, hdd_info, mgb, skincfg, zsea

Reviewed-on: #689
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Co-authored-by: IgorA <aie85playm@gmail.com>
2026-09-13 20:31:16 +00:00
Leency 7802c7b18a fat: fix stack imbalance on fatal hd_extend_file error (#631)
Build system / Build (en_US) (push) Successful in 3m6s
Build system / Build (es_ES) (push) Successful in 3m17s
Build system / Build (ru_RU) (push) Successful in 3m23s
Build system / Publish Images (push) Successful in 3m19s
The FAT/device error path in fat_Write jumped to the shared one-dword
epilogue with four dwords live, so ret returned into the error-code
slot and faulted in ring 0. Give the path its own named label.

Reviewed-on: #631
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
2026-09-12 21:25:21 +00:00
Leency 8a94db94a5 remove comments
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 17s
Test PR / Build (en_US) (pull_request) Successful in 2m18s
Test PR / Build (es_ES) (pull_request) Successful in 2m21s
Test PR / Build (ru_RU) (pull_request) Successful in 2m22s
Build system / Build (en_US) (push) Successful in 2m53s
Build system / Build (es_ES) (push) Successful in 2m56s
Build system / Build (ru_RU) (push) Successful in 3m0s
Build system / Publish Images (push) Successful in 4m58s
2026-09-11 18:51:30 +00:00
LeencyandClaude Opus 5 513af11464 kernel/net: raise the socket buffer size to 128 KiB
Summary: SOCKET_BUFFER_SIZE was 32 KiB, which caps a single TCP connection
at roughly 1 MB/s over a typical internet path regardless of the available
bandwidth.

Подробно:
The receive buffer size is the upper bound on the window a socket can
advertise, and a TCP connection cannot go faster than window / RTT. At the
old 4096*8 = 32 KiB, a path with a 32 ms round trip is limited to about
1 MB/s no matter how fast the link underneath is. Raising the buffer to
4096*32 = 128 KiB moves that ceiling to roughly 4 MB/s on the same path.

Nothing else needs adjusting: request_r_scale is derived from
SOCKET_BUFFER_SIZE in tcp_usreq, so the window scale we request grows with
the buffer automatically, and both tcp_output and tcp_respond clamp the
scaled value to the 16-bit header field. The constant keeps satisfying the
documented requirement of 4096*(power of two >= 8).

The cost is memory: each stream socket maps a send and a receive ring, so a
TCP socket now reserves 256 KiB of physical memory instead of 64 KiB (and
twice that in address space, since the rings are mirror-mapped). For a
browser holding a handful of connections open this is a few megabytes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 18:51:30 +00:00
Egor00f e0e8a35364 libc.obj: time.h using _ksys_get_clock, but this function not defined (#688)
Build system / Build (en_US) (push) Successful in 3m30s
Build system / Build (ru_RU) (push) Successful in 3m30s
Build system / Build (es_ES) (push) Successful in 3m38s
Build system / Publish Images (push) Successful in 3m13s
f2ea10c1cd/programs/develop/ktcc/libc.obj/include/time.h (L8)
Reviewed-on: #688
Co-authored-by: Egor00f <y.yarin@inbox.ru>
2026-09-08 20:41:45 +00:00
Matou1306 f2ea10c1cd fs/ext: Support INCOMPAT_EXTENTS, RO_COMPAT_DIR_NLINK, RO_COMPAT_HUGE_FILE. (#603)
Build system / Build (en_US) (push) Successful in 3m14s
Build system / Build (ru_RU) (push) Successful in 3m18s
Build system / Build (es_ES) (push) Successful in 3m23s
Build system / Publish Images (push) Successful in 3m40s
Extents writing support.
In addition, the file system can now write to file systems with dir_nlink, as long as the target directory doesn't have the index flag enabled (directories exceeding 64k subdirectories). It also supports huge_file, as long as the huge_file inode flag is not enabled on the file itself (files > 2TB).
This Pull Request depends on #584

What currently works:

- Merging a new allocation into the last extent when contiguous (.extentNext fast path)
- Adding a new extent entry into an existing leaf/root node that still has room (.addNewExtent)
- Creating the very first extent in an empty root (.newExtentRoot)
- Checksum maintenance via calc_extent_block_csum on writes to index/leaf blocks
- Truncation, including freeing leaves and collapsing an index entry back up the tree (.trim_tree/.trim_index), down to setting currentDepth = 0 when the whole tree empties
- Increasing the height of the tree and allocating new leaves.

Reviewed-on: #603
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: Matou1306 <mathieubotros@gmail.com>
2026-09-07 11:41:41 +00:00
Leency 302bf7e221 board: toggle kernel/user log with Tab (#682)
Build system / Build (ru_RU) (push) Successful in 3m56s
Build system / Build (en_US) (push) Successful in 4m1s
Build system / Build (es_ES) (push) Successful in 4m3s
Build system / Publish Images (push) Successful in 4m22s
Reviewed-on: #682
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-07 11:20:29 +00:00
IgorA a3af661ed6 libs/libimg: added support for saving 8-bit images in PNG format (#599)
Build system / Build (ru_RU) (push) Successful in 4m7s
Build system / Build (en_US) (push) Successful in 4m15s
Build system / Build (es_ES) (push) Successful in 4m23s
Build system / Publish Images (push) Successful in 4m10s
Еxample of an 8-bit png image with a palette https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/programs/develop/libraries/TinyGL/asm_fork/examples/text_2.png

Reviewed-on: #599
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: IgorA <aie85playm@gmail.com>
2026-09-07 11:14:21 +00:00
b00bl1k e74f989500 programs/system/terminal: switch to the serial driver (#638)
Build system / Build (es_ES) (push) Successful in 5m59s
Build system / Build (en_US) (push) Successful in 6m15s
Build system / Build (ru_RU) (push) Successful in 6m15s
Build system / Publish Images (push) Successful in 4m44s
Reworks Terminal to use the drivers/serial API instead of using UART registers directly, enabling virtual COM port (VCP) support in addition to physical ports.

- port field now accepts a numeric port id instead of a COMx name
- syscalls use `SF_*`/`SSF_*` named constants

Closes #604

Reviewed-on: #638
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: Alexey Ryabov <alex@b00bl1k.ru>
2026-09-07 10:37:40 +00:00
Leency 4fe3987e39 drivers/usbstor: limit one SCSI transfer to 240 sectors (#686)
Build system / Build (es_ES) (push) Successful in 4m3s
Build system / Build (en_US) (push) Successful in 4m3s
Build system / Build (ru_RU) (push) Successful in 4m5s
Build system / Publish Images (push) Successful in 4m8s
max_sectors_at_time only bounded a slice by the 16-bit transfer length
field of READ(10)/WRITE(10), i.e. 32 MB, so whatever the caller asked
for went to the device as a single command. The kernel disk cache hands
the driver up to CACHE_MAX_ALLOC_SIZE (4 MB) at once, so reading any
file larger than 4 MB produced one 4 MB bulk transfer.

USB sticks do not see such commands from other systems and some of them
wedge their firmware on it: the queue halts with XactErr and an
exhausted error counter, the device stops answering, drops off the bus
and re-enumerates in the middle of the operation. Observed on two
different sticks, reproducible on every file over 4 MB.

Cap a slice at 240 sectors (120 KB), the limit Linux usb-storage uses
for the same reason. The splitting loop was already there.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #686
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-07 07:45:25 +00:00
Sweetbread 060ec1a5d0 chore: codeowners
Test PR / Build (es_ES) (pull_request) Successful in 2m30s
Test PR / Build (en_US) (pull_request) Successful in 2m43s
Test PR / Build (ru_RU) (pull_request) Successful in 2m55s
Build system / Build (es_ES) (push) Successful in 4m49s
Build system / Build (en_US) (push) Successful in 4m57s
Build system / Build (ru_RU) (push) Successful in 4m56s
Build system / Publish Images (push) Successful in 3m57s
2026-09-03 11:59:18 +00:00
Sweetbread 882f1f0242 ci: use builtin GITEA_TOKEN
Test PR / Build (en_US) (pull_request) Successful in 1m52s
Test PR / Build (es_ES) (pull_request) Successful in 1m59s
Test PR / Build (ru_RU) (pull_request) Successful in 2m3s
Build system / Build (en_US) (push) Successful in 3m3s
Build system / Build (es_ES) (push) Successful in 3m6s
Build system / Build (ru_RU) (push) Successful in 3m10s
Build system / Publish Images (push) Successful in 3m47s
2026-09-03 11:48:08 +00:00
Leency 02070aa233 zeroconf: do not report IP conflict when device is gone (#677)
Build system / Build (en_US) (push) Successful in 3m30s
Build system / Build (es_ES) (push) Successful in 3m34s
Build system / Build (ru_RU) (push) Successful in 3m37s
Build system / Publish Images (push) Successful in 4m5s
Sysfn 76 returns -1 for a missing device. The ARP conflict counter
check in .maintain_link treats any change of the value as a new
conflict, so when a device disappeared the counter jumped 0 -> -1 -> 0
across the reconnect and a bogus "IP address conflict" notification
popped up on every replug of a USB network device.

Skip the check when the query fails.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #677
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-03 10:12:36 +00:00
Burer d0244f1513 apps/oberon07: migrate submodule to gitea (#680)
Build system / Build (en_US) (push) Successful in 3m34s
Build system / Build (es_ES) (push) Successful in 3m49s
Build system / Build (ru_RU) (push) Successful in 3m54s
Build system / Publish Images (push) Successful in 4m37s
Reviewed-on: #680
Reviewed-by: Егор Ярин <y.yarin@inbox.ru>
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Gleb Zaharov <risdeveau@lair.moe>
2026-09-03 10:06:44 +00:00
Leency 44465b3cc2 zeroconf: restart DHCP after network device removal (#676)
Build system / Build (ru_RU) (push) Successful in 4m23s
Build system / Build (en_US) (push) Successful in 4m40s
Build system / Build (es_ES) (push) Successful in 4m47s
Build system / Publish Images (push) Successful in 5m3s
Sysfn 74 returns -1 for a missing device, not 0, so the device-presence
check in .maintain_link never took the .link_down path and the interface
stayed in connected state forever. As a result DHCP was never restarted
when a device reappeared on the same slot (e.g. an Android phone
re-enumerating in RNDIS tethering mode with a new random MAC), leaving
the interface with a stale IP and a dead gateway.

Compare against 1 (Ethernet), the same way the .link_up? path already
does, so a vanished device properly resets the interface state and DHCP
runs again on reconnect.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #676
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-09-03 09:51:49 +00:00
Egor00f 1df9d8496d libshell & shell: use shell_api.h (#657)
Build system / Build (es_ES) (push) Successful in 3m46s
Build system / Build (en_US) (push) Successful in 3m55s
Build system / Build (ru_RU) (push) Successful in 4m27s
Build system / Publish Images (push) Successful in 5m28s
Use `shell_api.h` and the buffer structure in `shell` and `libshell` to avoid magic numbers and sync

Reviewed-on: #657
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: Egor00f <y.yarin@inbox.ru>
2026-09-02 08:25:57 +00:00
Leency 7917972a37 ac97snd: fix bug to play Cactus mp3
Build system / Build (en_US) (push) Successful in 3m16s
Build system / Publish Images (push) Successful in 15m36s
Test PR / Build (en_US) (pull_request) Successful in 1m54s
Test PR / Build (ru_RU) (pull_request) Successful in 2m4s
Test PR / Build (es_ES) (pull_request) Successful in 2m8s
Build system / Build (es_ES) (push) Successful in 3m9s
Build system / Build (ru_RU) (push) Successful in 3m13s
2026-09-01 22:48:45 +03:00
Burerandkolibrios-bot Bot 8334324d9c chore/submodules: bump kterm to upstream (#670)
Build system / Build (en_US) (push) Successful in 4m11s
Build system / Build (es_ES) (push) Successful in 4m19s
Build system / Build (ru_RU) (push) Successful in 4m26s
Build system / Publish Images (push) Successful in 5m10s
Co-authored-by: kolibri-bot <bot@kolibrios.org>
Reviewed-on: #670
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
2026-09-01 14:33:53 +00:00
2757ea7d3e libs/boxlib: rewrite editbox.asm (fix #652) (#662)
Build system / Build (en_US) (push) Successful in 3m35s
Build system / Build (es_ES) (push) Successful in 3m39s
Build system / Build (ru_RU) (push) Successful in 3m48s
Build system / Publish Images (push) Successful in 6m56s
Rewrite of the editbox widget. Binary layout and public API unchanged.

- much more readable code
- scroll step = actual chars that fit in the field (`visibleCount`, ex-`shift_old`), not hardcoded 8 (fixes #652)
- `edit_box` formalized as a fasm `struct` with named fields; unions add readable aliases (`caretPos`, `textLen`, `selectColor`, ...) to the old names
- `txCol` -> `txColor` (`BColor` union with per-channel access)
- clipboard: payload described by `BClipBuf` struct, content validated before paste, fixed paste arithmetic and a memory leak on read
- restored Ctrl+C
- fixed `not cx` truncation (buffer overflow), stale redraw in insert mode, division with uninitialized edx
- control flow untangled into procedures, net -94 lines

---------

Co-authored-by: Burer <burer@kolibrios.org>
Co-authored-by: ZReticules <my_mailbox_228@mail.ru>
Reviewed-on: #662
Reviewed-by: IgorA <22+igora@noreply.localhost>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: The Bird of Hermes <zlo.shustrik@mail.ru>
2026-09-01 14:26:21 +00:00
Burer bf8ae67dbf ci: restore functionality of old autobuilds system (#671)
Build system / Build (es_ES) (push) Successful in 3m35s
Build system / Publish Images (push) Successful in 4m48s
Build system / Build (ru_RU) (push) Successful in 3m39s
Build system / Build (en_US) (push) Successful in 3m44s
Restores what the new ci/ folder lost compared to the old autobuild server:
- `ci/latest` symlink to the newest build
- bare `kolibri.img` at `<lang>/data/data/kolibri.img` - the path emulators (v86) hardcode
- `distr.tar.gz` (distribution kit)
- build tree unpacked into `ci/<version>/<lang>/data/` for per-program downloads
- `sha256sums.txt` and `build.log` per language

Reviewed-on: #671
Reviewed-by: Gleb Zaharov <risdeveau@lair.moe>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: Burer <burer@kolibrios.org>
2026-09-01 15:02:56 +03:00
Leency 69bd99e991 kernel: check kernel_alloc result in font.inc (#663)
Build system / Build (en_US) (push) Successful in 2m27s
Build system / Build (ru_RU) (push) Successful in 2m32s
Build system / Build (es_ES) (push) Successful in 2m39s
Build system / Publish Images (push) Successful in 1m59s
This avoid taskbar and other apps crash when no free mem.

Reviewed-on: #663
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-08-31 12:21:10 +00:00
weronika-saturday 3bde56821f data/skins: Zune skin from WindowsXP for KolibriOS (#665)
Build system / Publish Images (push) Successful in 3m3s
Build system / Build (es_ES) (push) Successful in 2m21s
Build system / Build (en_US) (push) Successful in 2m24s
Build system / Build (ru_RU) (push) Successful in 2m27s
Today is the 20th anniversary of Microsoft’s Zune player.
I ported the theme of Zune from Windows XP.
This is my first experience in creating skins for KolibriOS.

Reviewed-on: #665
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Alexey Ryabov <alex@b00bl1k.ru>
Co-authored-by: Weronika Saturday <saturdayweronika@gmail.com>
2026-08-30 06:53:56 +00:00
Leency 2c22604f39 kernel_free, not free_kernel_space: the rings' physical pages must return to the bitmap too. (#664)
Build system / Build (ru_RU) (push) Successful in 2m32s
Build system / Publish Images (push) Successful in 1m53s
Build system / Build (en_US) (push) Successful in 2m25s
Build system / Build (es_ES) (push) Successful in 2m28s
The mirror mapping is safe - release_pages frees each frame once.

Reviewed-on: #664
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-08-28 20:37:27 +00:00
Leency de952921ee drivers/usb: xHCI (USB3) controller driver (#666)
Build system / Build (en_US) (push) Successful in 2m10s
Build system / Build (es_ES) (push) Successful in 2m12s
Build system / Build (ru_RU) (push) Successful in 2m19s
Build system / Publish Images (push) Successful in 2m7s
Serves PCI class 0C0330: LS/FS/HS devices on USB2 ports, SuperSpeed on
USB3 ports. The kernel stack knows only USB2 speeds, so SuperSpeed is
reported as high-speed and handled inside the driver. Falls back to
polling when the controller has no usable interrupt line.

Tested: flash drives, an external SSD, mice, keyboards.
Reviewed-on: #666
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-08-28 12:25:38 +00:00
Leency 7f44db1b7f free3d04: use libimg and clean png file to decrease file size (30 KB => 16.5 KB) (#667)
Build system / Build (en_US) (push) Successful in 3m55s
Build system / Build (ru_RU) (push) Successful in 4m6s
Build system / Build (es_ES) (push) Successful in 4m13s
Build system / Publish Images (push) Successful in 3m3s
Reviewed-on: #667
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-08-28 10:21:27 +00:00
Doczom f143ca1928 Kernel/disk.inc: fixed getting the disk partition number #651
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 18s
Test PR / Build (en_US) (pull_request) Successful in 2m17s
Test PR / Build (ru_RU) (pull_request) Successful in 2m18s
Test PR / Build (es_ES) (pull_request) Successful in 2m24s
Build system / Build (en_US) (push) Successful in 2m47s
Build system / Build (es_ES) (push) Successful in 2m50s
Build system / Build (ru_RU) (push) Successful in 2m52s
Build system / Publish Images (push) Successful in 2m49s
2026-08-22 10:47:21 +00:00
Matou1306andBurer 931071a0e9 kernel/fs: new SF's 70.11 (create symlink) and 70.12 (read symlink) with EXT driver support (#570)
Build system / Build (es_ES) (push) Successful in 2m33s
Build system / Build (en_US) (push) Successful in 2m39s
Build system / Build (ru_RU) (push) Successful in 2m43s
Build system / Publish Images (push) Successful in 3m28s
Tested the changes on qemu and umka and everything appears to be working fine

---------

Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #570
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Егор Ярин <y.yarin@inbox.ru>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: Matou <mathieubotros@gmail.com>
2026-08-21 10:30:06 +00:00
Matou1306andBurer bed9528756 fs/ext: support flex-bg writing and update new blocks allocation selection (#584)
Build system / Build (en_US) (push) Successful in 2m27s
Build system / Build (es_ES) (push) Successful in 2m29s
Build system / Build (ru_RU) (push) Successful in 2m35s
Build system / Publish Images (push) Successful in 2m5s
Update `extfsExtentAlloc` to take edi as a goal block to start allocation at the previous block's group, falling back to the file's inode block group if edi is zero.

---------

Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #584
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: Matou <mathieubotros@gmail.com>
2026-08-18 07:02:57 +00:00
Egor00f 570a432a84 libc.obj: fix _ksys_read_dir (#650)
Build system / Build (en_US) (push) Successful in 2m26s
Build system / Build (es_ES) (push) Successful in 2m32s
Build system / Build (ru_RU) (push) Successful in 2m35s
Build system / Publish Images (push) Successful in 2m31s
and update `libc.obj`: update `opendir` for new `_ksys_read_dir`

Thanks to @Burer for spotting this mistake.

Reviewed-on: #650
Co-authored-by: Egor00f <y.yarin@inbox.ru>
2026-08-17 17:24:24 +00:00
Leency 1215116155 add netsurf app that download and run (or only run) the NeSurf (#648)
Build system / Build (en_US) (push) Successful in 2m11s
Build system / Build (es_ES) (push) Successful in 2m14s
Build system / Build (ru_RU) (push) Successful in 2m22s
Build system / Publish Images (push) Successful in 2m1s
+ update icon path, add to menu

Reviewed-on: #648
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-08-17 16:32:03 +00:00
Egor00f e470ef5db5 libc.obj: fix opendir (#645)
Build system / Build (en_US) (push) Successful in 2m14s
Build system / Build (ru_RU) (push) Successful in 2m26s
Build system / Build (es_ES) (push) Successful in 2m30s
Build system / Publish Images (push) Successful in 2m31s
Changes:
- [x] ignore `EOF` error
- [x] fix buf size
  `520` and `264` were mixed up
- [x] Separate checks for `malloc` and `_ksys_read_dir`
- [x] fix some potential errors
- [x] update `dir_example.c`
  + it may have page fail if run it from `shell`, because it try call `con_set_flags`
  + fix `mkdir` test
  + show `opendir` error

Reviewed-on: #645
Co-authored-by: Egor00f <y.yarin@inbox.ru>
2026-08-17 15:42:54 +00:00
Burerandkolibrios-bot Bot 24d1b5877a chore/submodules: bump kterm to upstream (#644)
Build system / Build (es_ES) (push) Successful in 2m15s
Build system / Build (ru_RU) (push) Successful in 2m22s
Build system / Build (en_US) (push) Successful in 2m27s
Build system / Publish Images (push) Successful in 1m52s
Co-authored-by: kolibri-bot <bot@kolibrios.org>
Reviewed-on: #644
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
2026-08-14 16:12:31 +00:00
Burer aa8913ea33 games/dino: binary size optimization (fix #537) (#632)
Build system / Build (en_US) (push) Successful in 3m8s
Build system / Build (es_ES) (push) Successful in 3m7s
Build system / Build (ru_RU) (push) Successful in 3m9s
Build system / Publish Images (push) Successful in 2m29s
- Size (fit into 8192 bytes or 16 IMG sectors):
  - Drop `ulist` in favor of static arrays
  - Dropping `malloc`/`free`/`exit`; `sprintf`, `pow`, `strlen` and 64-bit division no longer pull in libc and libtcc1
  - Dead code removed

- Rendering:
  - libimg dropped. `png2h.py` turns the original PNG into a palette-indexed atlas; the blit writes a 32bpp buffer, sysfn 65 puts it on screen - the same call `img_draw` made. No runtime PNG decode, output pixel-identical. The buffer ends at the ground line: 18% fewer pixels per frame

- Bugs fixed:
  - Every fourth pterodactyl was invisible and unhittable: `getRandomNumber` is inclusive, so `yPosArr[3]` read the next field (999) and the bird spawned off-screen
  - Releasing the jump key never shortened the first jump: gated on a flag set only after the intro; Chrome gates on the loop being scheduled
  - Flap rate `1000/6` truncated to 166, `minSpeed` 8.5 to 8 - birds came earlier than in Chrome
  - Hardcoded caption height clipped the window on every non-default skin
  - A maximum jump left the buffer and cut off the dino's head; the playfield is centered now
  - Obstacles and clouds leaked: nodes were freed, their data never

- Localization:
  - Caption localized to EN/RU/ES via `CONFIG_LANG`, fits every skin in the tree

Reviewed-on: #632
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
2026-08-14 13:51:14 +00:00
Leency 647f35ea10 XDPascal: smart linking (#646)
Build system / Build (es_ES) (push) Successful in 2m28s
Build system / Build (en_US) (push) Successful in 2m32s
Build system / Build (ru_RU) (push) Successful in 2m39s
Build system / Publish Images (push) Successful in 2m35s
XDPascal для Колибри и Винды. С примерами.

Компиляторы убирают из бинарника недостижимые процедуры: два прохода,
на первом строится граф вызовов, на втором код мёртвых процедур не пишется.
Бинарники меньше в 1.5-5 раз. Ключ -nosmart отключает, вывод при этом
побайтово совпадает со старым компилятором.

Также снимаются кавычки с аргументов командной строки: без этого
make.bat не работал со сборкой не через Delphi.

xdpw_2020 - прежний компилятор, xdpw_2026 - новый.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #646
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-08-13 11:54:35 +00:00
Doczom f44ceb560c macros/format: fixed the flag for having an import table in KX format
Test PR / Build (es_ES) (pull_request) Successful in 2m36s
Test PR / Build (en_US) (pull_request) Successful in 2m38s
Test PR / Build (ru_RU) (pull_request) Successful in 2m40s
Build system / Build (ru_RU) (push) Successful in 3m10s
Build system / Build (en_US) (push) Successful in 3m13s
Build system / Build (es_ES) (push) Successful in 3m16s
Build system / Publish Images (push) Successful in 2m23s
2026-08-11 21:28:53 +05:00
Burer 6defa11a9e kernel/docs, programs: rename SF 51 and SF 77 constants (fix #321) (#640)
Test PR / Build (en_US) (pull_request) Successful in 4m7s
Build system / Build (en_US) (push) Successful in 4m28s
Test PR / Build (es_ES) (pull_request) Successful in 4m21s
Build system / Build (es_ES) (push) Successful in 4m39s
Build system / Build (ru_RU) (push) Successful in 4m43s
Test PR / Build (ru_RU) (pull_request) Successful in 1m24s
Build system / Publish Images (push) Successful in 2m0s
| SF | SSF | Old Name | Name Name |
|---|---|---|---|
| 51 | — | `SF_CREATE_THREAD` | `SF_THREAD_CONTROL` |
| 77 | — | `SF_FUTEX` | `SF_POSIX` |
| 77 | 0 | `SSF_CREATE` | `SSF_FUTEX_CREATE` |
| 77 | 1 | `SSF_DESTROY` | `SSF_FUTEX_DESTROY` |
| 77 | 2 | `SSF_WAIT` | `SSF_FUTEX_WAIT` |
| 77 | 3 | `SSF_WAKE` | `SSF_FUTEX_WAKE` |
| 77 | 10 | `SSF_FILE_READ` | `SSF_FD_READ` |
| 77 | 11 | `SSF_FILE_WRITE` | `SSF_FD_WRITE` |
| 77 | 13 | `SSF_PIPE_CREATE` | `SSF_FD_PIPE2` |

Reviewed-on: #640
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
2026-08-09 19:08:15 +00:00
LeencyandBurer 944d74f013 drivers/hdaudio: add ring buffer for unsolicited events (#455)
Build system / Build (es_ES) (push) Successful in 2m15s
Build system / Build (ru_RU) (push) Successful in 2m19s
Build system / Build (en_US) (push) Successful in 2m23s
Build system / Publish Images (push) Successful in 1m46s
I had an issue with 100% cpu load caused by this commit be847c5e1f
This PC is HP dc5800. Its audio card is PCI\VEN_8086&DEV_293E&REV_02 (ICH9 - 82801I) with build-in speaker.

So I Gemini wrote some code for me:

> This code implements a circular buffer to temporarily store unsolicited events, allowing the interrupt handler to quickly save data and immediately release the CPU. Now, instead of placing a direct load on the system, a background timer periodically "picks up" the accumulated events from this buffer and processes them safely.

Now it fixed on my PC. Also I've tested it on two machines and it also works well. Please take a look.

---------

Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #455
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Ivan B <1+dunkaist@noreply.localhost>
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-08-08 15:46:02 +00:00
Leency 2bebbcbdc3 kernel/fs: narrow the UTF16to8 input to ax (#633)
Build system / Build (es_ES) (push) Successful in 2m9s
Build system / Build (ru_RU) (push) Successful in 2m13s
Build system / Build (en_US) (push) Successful in 2m18s
Build system / Publish Images (push) Successful in 2m32s
Load characters with lodsw only ever set ax. Anything left in the high half - including what this routine's own three-byte branch leaves there - would then push every following character into a longer form: an ASCII name off a Joliet CD came out as overlong three-byte sequences from the second character on. Narrow the input here, so every caller is safe.

Reviewed-on: #633
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-08-08 15:30:25 +00:00
4ds-devandBurer 201e8b2de3 apps/cedit: menu for managing supported languages, universal language configs (#554)
Build system / Build (en_US) (push) Successful in 2m4s
Build system / Build (es_ES) (push) Successful in 2m10s
Build system / Build (ru_RU) (push) Successful in 2m15s
Build system / Publish Images (push) Successful in 2m15s
- all languages are configured via cedit.ini (the “edit” button in the “languages” menu)
- build/run/debug commands are also configured via cedit.ini
- new languages can be added via cedit.ini
- zator language has been added

---------

Co-authored-by: Burer <burer@kolibrios.org>
Reviewed-on: #554
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Alexey Ryabov <alex@b00bl1k.ru>
Co-authored-by: 4ds-dev <4ds.dev@gmail.com>
2026-08-07 07:57:14 +00:00
Burer 0390ad41e4 apps/klavisha: move to iso (#635)
Build system / Build (es_ES) (push) Successful in 2m17s
Build system / Build (en_US) (push) Successful in 2m25s
Build system / Build (ru_RU) (push) Successful in 2m31s
Build system / Publish Images (push) Successful in 1m53s
Klavisha takes 11 sectors in IMG, and is included only in RU build.
I propose move it to ISO to free space on IMG and make it more consisntent.

Reviewed-on: #635
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Alexey <alex@b00bl1k.ru>
2026-08-07 07:44:31 +00:00
b00bl1k 2515d1fa37 drivers/serial: implement serial ports enumeration (#629)
Build system / Build (es_ES) (push) Successful in 3m22s
Build system / Build (en_US) (push) Successful in 3m31s
Build system / Build (ru_RU) (push) Successful in 3m39s
Build system / Publish Images (push) Successful in 2m15s
This PR adds a new enum_ports call to the serial driver's control API that lets user-mode programs list the serial ports currently registered in the system.

It also updates debug output strings, changes the USB FTDI driver's service procedure name, and removes duplicated code from the baud rate calculation.

Reviewed-on: #629
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: Alexey Ryabov <alex@b00bl1k.ru>
2026-08-07 04:40:23 +00:00
Egor00f da0e6f492b libc.obj: export missed vfprintf (#634)
Build system / Build (en_US) (push) Successful in 2m36s
Build system / Build (es_ES) (push) Successful in 2m38s
Build system / Build (ru_RU) (push) Successful in 2m41s
Build system / Publish Images (push) Successful in 2m9s
The `vfprintf` function is declared in the header files, but is not exported in the library.

Reviewed-on: #634
Co-authored-by: Egor00f <y.yarin@inbox.ru>
2026-08-06 13:52:14 +00:00
Egor00f 3c2bdfb418 Обновить programs/develop/ktcc/libc.obj/source/stdio/puts.c
Test PR / Build (es_ES) (pull_request) Successful in 1m50s
Test PR / Build (ru_RU) (pull_request) Successful in 1m56s
Test PR / Build (en_US) (pull_request) Successful in 1m58s
Build system / Build (en_US) (push) Successful in 2m10s
Build system / Build (es_ES) (push) Successful in 2m13s
Build system / Build (ru_RU) (push) Successful in 2m17s
Build system / Publish Images (push) Successful in 2m22s
2026-08-05 17:24:27 +00:00
Egor00f 67770ec3f4 libc.obj: implement console output via SHELL (#354)
Test PR / Build (ru_RU) (pull_request) Successful in 1m49s
Test PR / Build (en_US) (pull_request) Successful in 1m54s
Test PR / Build (es_ES) (pull_request) Successful in 1m57s
Adding console I/O via the `SHELL`.

Demonstration of [http_tcp_demo.c](https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/programs/develop/ktcc/libc.obj/samples/http_tcp_demo.c):
<video src="attachments/847d7d19-3d67-480d-80c8-6d678af61a43" title="Запись экрана от 2026-03-07 13-55-50.mp4" controls></video>

- [x] output
- [x] multithread
  - [x] add mutex
  - [x] multithread tests

Reviewed-on: #354
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Co-authored-by: Egor00f <y.yarin@inbox.ru>
2026-08-04 12:49:19 +05:00
Egor00f 76294451d2 libc.obj: implement console output via SHELL (#354)
Build system / Build (en_US) (push) Successful in 3m18s
Build system / Build (es_ES) (push) Successful in 3m21s
Build system / Build (ru_RU) (push) Successful in 2m28s
Build system / Publish Images (push) Successful in 2m39s
Adding console I/O via the `SHELL`.

Demonstration of [http_tcp_demo.c](https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/programs/develop/ktcc/libc.obj/samples/http_tcp_demo.c):
<video src="attachments/847d7d19-3d67-480d-80c8-6d678af61a43" title="Запись экрана от 2026-03-07 13-55-50.mp4" controls></video>

- [x] output
- [x] multithread
  - [x] add mutex
  - [x] multithread tests

Reviewed-on: #354
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Co-authored-by: Egor00f <y.yarin@inbox.ru>
2026-08-04 07:10:36 +00:00
LeencyandClaude Opus 5 031fe62338 kernel/net: fix the TCP keepalive timer expiry handler (#621)
Build system / Build (es_ES) (push) Successful in 2m12s
Build system / Build (en_US) (push) Successful in 2m18s
Build system / Build (ru_RU) (push) Successful in 2m18s
Build system / Publish Images (push) Successful in 1m40s
Summary: the keepalive handler compared the wrong field against the TCB
state constants, and walked into freed memory when the socket it killed was
released by tcp_disconnect.

Details:
Two independent defects in the same branch of tcp_timer_640ms.

First, the state test read TCP_SOCKET.state. That field is the inherited
SOCKET.state, an SS_* bitmask, not the TCB state machine; comparing it
against TCPS_ESTABLISHED compared a bitmask against an enum and decided
nothing meaningful. The TCB state lives in t_state. The comparison is also
changed from `ja` to `jae`, so only embryonic connections -- those whose
handshake never completed within TCP_time_keep_init -- are torn down here.
A synchronized connection now always falls through to .dont_kill, where it
either gets a keepalive probe (SO_KEEPALIVE set) or simply rearms the timer,
as in BSD. Previously an idle but perfectly healthy connection could be
dropped without the application ever asking for keepalives.

Second, the kill path did

        push    eax
        call    tcp_disconnect
        pop     eax
        jmp     .loop

and .loop dereferences SOCKET.NextPtr of that socket. But tcp_disconnect
jumps straight to tcp_close for a not-yet-synchronized connection, and
tcp_close calls socket_free -- so NextPtr was read out of freed kernel heap
and the timer thread continued its walk down a dangling pointer. The
successor is now saved before the call and the loop resumes at .check_only,
which is exactly what the timed-wait branch at the end of the same loop
already does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #621
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
2026-08-03 18:28:35 +00:00
LeencyandClaude Opus 5 8766bfc546 kernel/net: free TCP sockets closed before the handshake completes (#620)
Build system / Build (en_US) (push) Successful in 3m21s
Build system / Build (es_ES) (push) Successful in 3m23s
Build system / Build (ru_RU) (push) Successful in 1m37s
Build system / Publish Images (push) Successful in 2m16s
Summary: socket_close() skipped both tcp_disconnect and socket_free for any
TCP socket that was not yet in the SS_ISCONNECTED state, leaking the socket
structure and leaving it on the net_sockets list forever.

Details:
The SS_ISCONNECTED gate in socket_close covered only fully established
connections. A socket closed while in SYN_SENT, SYN_RECEIVED or LISTEN, or
one that never connected at all, fell through to a bare `ret`: it was
neither disconnected nor freed. The 4 KiB socket structure and its two ring
buffers stayed allocated, the socket kept its place on net_sockets, its
timers kept being decremented by tcp_timer_640ms, and SOCKET.TID kept
pointing at a thread that was about to exit. A browser or any other
application that opens connections which fail to establish (refused,
filtered, or simply cancelled by the user) leaked one socket per attempt.

The gate is not needed: tcp_disconnect dispatches on the TCB state itself
and jumps straight to tcp_close -- which calls socket_free -- whenever
t_state is below TCPS_ESTABLISHED. Dropping the test therefore routes the
not-yet-synchronized cases to exactly the cleanup they were missing, and
leaves the established path untouched. The SS_ISDISCONNECTING test is kept,
so a second close() on a socket already shutting down is still a no-op.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #620
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
2026-08-03 18:08:29 +00:00
hidnplayr 2db92868a9 Updated IPv4 routing to perform best guess instead of hardcoded default device, until we have full routing. (#613)
Build system / Build (ru_RU) (push) Successful in 2m8s
Build system / Build (en_US) (push) Successful in 2m12s
Build system / Build (es_ES) (push) Successful in 2m17s
Build system / Publish Images (push) Successful in 1m49s
#612

Reviewed-on: #613
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Co-authored-by: hidnplayr <hidnplayr@gmail.com>
2026-08-02 16:54:07 +00:00
IgorA 4bdee82489 apps/palitra: small improvements (#626)
Build system / Build (es_ES) (push) Successful in 2m15s
Build system / Build (ru_RU) (push) Successful in 2m20s
Build system / Build (en_US) (push) Successful in 2m27s
Build system / Publish Images (push) Successful in 2m56s
- redraw sliders while moving the mouse,
- slider redrawing optimized

Reviewed-on: #626
Reviewed-by: Kiril Lipatov <lipatov.kiril@gmail.com>
Reviewed-by: Burer <burer@kolibrios.org>
Co-authored-by: IgorA <aie85playm@gmail.com>
2026-08-02 14:00:20 +00:00
Burer b9fe23b7b2 drivers: add serial and usbftdi to img (#628)
Build system / Build (en_US) (push) Successful in 2m21s
Build system / Build (es_ES) (push) Successful in 2m6s
Build system / Build (ru_RU) (push) Successful in 2m5s
Build system / Publish Images (push) Successful in 1m52s
By the request of @b00bl1k.

Reviewed-on: #628
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Reviewed-by: b00bl1k <alex@b00bl1k.ru>
2026-08-02 09:01:07 +00:00
b00bl1k d33a03c2e4 kernel/AHCI: preserve ebx/esi/edi in ahci_irq_handler
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 18s
Test PR / Build (en_US) (pull_request) Successful in 2m12s
Test PR / Build (ru_RU) (pull_request) Successful in 2m15s
Test PR / Build (es_ES) (pull_request) Successful in 2m18s
Build system / Build (es_ES) (push) Successful in 2m20s
Build system / Build (en_US) (push) Successful in 2m23s
Build system / Build (ru_RU) (push) Successful in 2m25s
Build system / Publish Images (push) Successful in 2m23s
2026-08-01 15:58:09 +05:00
LeencyandClaude Opus 5 35f35b39e7 kernel/net: scale the window before clamping it in tcp_respond
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 20s
Test PR / Build (en_US) (pull_request) Successful in 1m51s
Test PR / Build (es_ES) (pull_request) Successful in 1m56s
Test PR / Build (ru_RU) (pull_request) Successful in 2m0s
Build system / Build (en_US) (push) Successful in 2m7s
Build system / Build (es_ES) (push) Successful in 2m13s
Build system / Build (ru_RU) (push) Successful in 2m21s
Build system / Publish Images (push) Successful in 1m46s
Summary: tcp_respond clamped the free receive space to 65535 and only then
applied RCV_SCALE, so scaled ACKs and keepalives advertised a window far
smaller than the one actually available.

Подробно:
The window field of a TCP header is 16 bits wide and, when window scaling is
in effect, carries the free space shifted right by RCV_SCALE. The two
operations therefore have to happen in that order: shift first, then clamp
the result to TCP_max_win.

tcp_respond did the opposite. With a receive buffer larger than 64 KiB and
RCV_SCALE = 2, free space of 128 KiB was first cut down to 65535 and then
shifted to 16383, announcing 64 KiB instead of the full 128 KiB. The larger
the buffer and the scale factor, the worse the under-advertisement -- the
window only ever shrank, so the effect was lost throughput rather than
corruption, but it silently defeated window scaling on exactly the responses
that carry the window most often.

tcp_output already gets this right (it compares against TCP_max_win shl
RCV_SCALE before writing the field); tcp_respond now agrees with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 17:45:52 +00:00
Leency a020a2c434 kernel/net: fix wild write in tcp_set_persist
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 18s
Test PR / Build (es_ES) (pull_request) Successful in 2m27s
Test PR / Build (ru_RU) (pull_request) Successful in 2m31s
Test PR / Build (en_US) (pull_request) Successful in 2m34s
Build system / Build (en_US) (push) Successful in 2m10s
Build system / Build (es_ES) (push) Successful in 2m14s
Build system / Build (ru_RU) (push) Successful in 2m20s
Build system / Publish Images (push) Successful in 1m45s
tcp_set_persist takes the socket pointer in eax and uses ebx as a
scratch register to compute the RTO:

        mov     ebx, [eax + TCP_SOCKET.t_srtt]
        shr     ebx, 2
        add     ebx, [eax + TCP_SOCKET.t_rttvar]
        shr     ebx, 1
        mov     cl, [eax + TCP_SOCKET.t_rxtshift]
        shl     ebx, cl

By the time the persist timer is armed ebx therefore holds the timeout
value, not the socket. The flag store nevertheless went through ebx, so
it wrote to the linear address <RTO> + TCP_SOCKET.timer_flags -- an
unmapped low address -- instead of setting timer_flag_persist on the
socket.

Any TCP connection whose peer advertises a zero window takes this path
from tcp_output.enter_persist and faults the kernel:

        K : Page fault
        K : EBX : 0000000A
        K : EIP : 80037DF3   (tcp_set_persist, the flag store)
        K : Process - forced terminate PID: 00000005

Observed with NetSurf on a HTTP/2 connection to www.redhat.com, where
twelve multiplexed streams closed the receive window. Store the flag
through eax, which tcpt_rangeset leaves untouched.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 17:32:55 +00:00
Leency 77d600c663 open: finally fix file association (#594)
Build system / Build (en_US) (push) Successful in 2m10s
Build system / Build (es_ES) (push) Successful in 2m21s
Build system / Build (ru_RU) (push) Successful in 2m21s
Build system / Publish Images (push) Successful in 3m16s
htm association with Netfurf never worked normally before!

Reviewed-on: #594
Reviewed-by: Burer <burer@kolibrios.org>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-07-30 02:34:26 +00:00
LeencyandClaude Opus 5 f7dd4033ba kernel/net: honour the window scale factor advertised by the peer (#619)
Build system / Build (es_ES) (push) Successful in 2m21s
Build system / Build (en_US) (push) Successful in 2m24s
Build system / Build (ru_RU) (push) Successful in 2m28s
Build system / Publish Images (push) Successful in 3m24s
Summary: the received window scale option was stored into SND_SCALE, which
the connection setup code then immediately overwrote with zero, so every
peer window was interpreted unscaled.

Details:
RFC 1323 negotiation is completed in two places -- the SYN_RECEIVED branch
and the active-open branch of tcp_input. Both do

        mov     ax, word[ebx + TCP_SOCKET.requested_s_scale]
        mov     word[ebx + TCP_SOCKET.SND_SCALE], ax

relying on the declared order of the four adjacent bytes SND_SCALE,
RCV_SCALE, requested_s_scale, request_r_scale to move both factors at once.
requested_s_scale, however, was never filled in: the option parser wrote the
peer's shift count into SND_SCALE directly, and that value was then clobbered
by the word move with the zero left in requested_s_scale by socket_alloc.

The result was that SND_SCALE ended up 0 on every connection while
TF_RCVD_SCALE was set, so a peer advertising, say, 64 KiB with a shift of 7
was read as advertising 512 bytes. Sending to any modern host was throttled
to a fraction of the real window.

The parser now stores into requested_s_scale, where the setup code expects
it, and clamps the value to TCP_max_winshift (14) as required by RFC 1323 --
a peer sending a larger shift must not be allowed to make our SND_WND
computation shift out of range.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reviewed-on: #619
Reviewed-by: hidnplayr <hidnplayr@gmail.com>
Reviewed-by: Mikhail Frolov <mixa.frolov2003@gmail.com>
Co-authored-by: leency <lipatov.kiril@gmail.com>
2026-07-30 02:26:39 +00:00
314 changed files with 66269 additions and 12495 deletions

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
# =============================================================================
# Apps
# User-facing applications, games, multimedia, UI and desktop resources
# =============================================================================
^programs/(cmm|demos|emulator|games|media|other)/.* @KolibriOS/apps
^contrib/(games|media|other)/.* @KolibriOS/apps
^skins/.* @KolibriOS/apps
# =============================================================================
# System
# Kernel, drivers, filesystems, SDK, libraries, toolchain and system utilities
# =============================================================================
^kernel/.* @KolibriOS/system
^drivers/.* @KolibriOS/system
^programs/(bcc32|develop|fs|hd_load|system|testing)/.* @KolibriOS/system
^contrib/(C_Layer|sdk|toolchain)/.* @KolibriOS/system
# Shared system/API includes in programs/
^programs/[^/]+\\.inc$ @KolibriOS/system
# =============================================================================
# Network
# Network stack, network drivers, protocols, libraries and network applications
# =============================================================================
^kernel/trunk/network/.* @KolibriOS/network
^drivers/ethernet/.* @KolibriOS/network
^drivers/(mii|netdrv)\\.inc$ @KolibriOS/network
^programs/network/.* @KolibriOS/network
^programs/network\\.inc$ @KolibriOS/network
^programs/develop/libraries/(http|network|kos_mbedtls)/.* @KolibriOS/network
^contrib/network/.* @KolibriOS/network
# =============================================================================
# DevOps
# CI/CD, repository infrastructure, build system and autobuild configuration
# =============================================================================
^\\.gitea/.* @KolibriOS/devops
^_tools/.* @KolibriOS/devops
^\\.gitmodules$ @KolibriOS/devops
^build\\.txt$ @KolibriOS/devops
^tup\\.config\\.template$ @KolibriOS/devops
+35
View File
@@ -19,3 +19,38 @@
owner: "{{ storage_user }}"
group: "{{ storage_user }}"
mode: preserve
# per-program binaries browsable at <version>/<lang>/data/, like on the old builds server
- name: Creating build tree folders
ansible.builtin.file:
path: "{{ storage_path }}/{{ version }}/{{ item | basename | regex_replace('\\.tar\\.gz$', '') }}/data"
state: directory
owner: "{{ storage_user }}"
group: "{{ storage_user }}"
mode: '0755'
with_fileglob: "{{ tree_artifact_path }}/*.tar.gz"
- name: Unpacking build trees
ansible.builtin.unarchive:
src: "{{ item }}"
dest: "{{ storage_path }}/{{ version }}/{{ item | basename | regex_replace('\\.tar\\.gz$', '') }}/data"
owner: "{{ storage_user }}"
group: "{{ storage_user }}"
with_fileglob: "{{ tree_artifact_path }}/*.tar.gz"
# stable URL for the newest build: <storage_path>/latest/<lang>/...
- name: Updating latest symlink
ansible.builtin.file:
src: "{{ version }}"
dest: "{{ storage_path }}/latest"
state: link
force: true
owner: "{{ storage_user }}"
group: "{{ storage_user }}"
# emulators hardcode <site root>/<lang>/data/data/kolibri.img; storage_path is the ci folder, one level under the site root
- name: Sending bare images to stable emulator paths
ansible.builtin.copy:
src: "{{ stable_artifact_path }}/"
dest: "{{ storage_path }}/../"
mode: preserve
+83 -22
View File
@@ -162,12 +162,13 @@ jobs:
tup init
tup variant ${{ matrix.lang }}.config
# build the image for language variant
# build the image for language variant; keep the tup log for publishing
- name: Build KolibriOS
run: |
set -o pipefail
export PATH=/home/autobuild/tools/win32/bin:$PATH
source kos32-export-env-vars ${{ gitea.workspace }}
tup build-${{ matrix.lang }}
tup build-${{ matrix.lang }} 2>&1 | tee build.log
# stamp the cache with its commit so later builds diff against it
- name: Record cache base commit
@@ -181,15 +182,26 @@ jobs:
id: vars
run: echo "descr=$(git describe --tags)" >> $GITEA_OUTPUT
# rename build outputs to their final names so artifacts are bare files
- name: Rename images
# stage build outputs under their final names, plus distribution kit and checksums
- name: Prepare artifacts
run: |
set -e
BASE="kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}"
for ext in img iso raw; do
cp "build-${{ matrix.lang }}/data/kolibri.$ext" \
"kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.$ext"
cp "build-${{ matrix.lang }}/data/kolibri.$ext" "$BASE.$ext"
done
# zip: distr targets Windows/DOS users, Explorer opens it natively
(cd "build-${{ matrix.lang }}/data" && zip -r -9 -q "${{ gitea.workspace }}/$BASE.distr.zip" distribution_kit)
# whole build tree for per-program downloads; the big images ship separately
tar -C "build-${{ matrix.lang }}" \
--exclude './data/kolibri.iso' \
--exclude './data/kolibri.raw' \
--exclude './data/distribution_kit' \
-czf "$BASE.tree.tar.gz" .
sha256sum "$BASE".img "$BASE".iso "$BASE".raw "$BASE".distr.zip > "$BASE.sha256sums.txt"
mv build.log "$BASE.build.log"
#publish the three images; longer retention for the floppy image.
# publish the images; longer retention for the floppy image
- name: Upload floppy image
uses: actions/upload-artifact@v3
with:
@@ -211,6 +223,34 @@ jobs:
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.raw
retention-days: 15
- name: Upload distribution kit
uses: actions/upload-artifact@v3
with:
name: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.distr.zip
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.distr.zip
retention-days: 30
- name: Upload checksums
uses: actions/upload-artifact@v3
with:
name: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.sha256sums.txt
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.sha256sums.txt
retention-days: 90
- name: Upload build log
uses: actions/upload-artifact@v3
with:
name: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.build.log
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.build.log
retention-days: 90
- name: Upload build tree
uses: actions/upload-artifact@v3
with:
name: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.tree.tar.gz
path: kolibrios-${{ steps.vars.outputs.descr }}-${{ matrix.lang }}.tree.tar.gz
retention-days: 15
deploy:
name: "Publish Images"
runs-on: ubuntu-latest
@@ -235,31 +275,50 @@ jobs:
run: |
set -eu
rm -rf ./norm-artifacts
mkdir -p ./norm-artifacts
rm -rf ./norm-artifacts ./stable-artifacts ./tree-artifacts
mkdir -p ./norm-artifacts ./stable-artifacts ./tree-artifacts
find ./artifacts -type f \( \
-name 'kolibrios-*.img' -o \
-name 'kolibrios-*.iso' -o \
-name 'kolibrios-*.raw' \
\) | while read -r file; do
fname="$(basename "$file")" # kolibrios-<descr>-<lang>.<ext>
name_without_ext="${fname%.*}"
lang="${name_without_ext##*-}"
find ./artifacts -type f -name 'kolibrios-*' | while read -r file; do
fname="$(basename "$file")" # kolibrios-<descr>-<lang>.<suffix>
case "$fname" in
*.tree.tar.gz) stem="${fname%.tree.tar.gz}";;
*.distr.zip) stem="${fname%.distr.zip}";;
*.sha256sums.txt) stem="${fname%.sha256sums.txt}";;
*.build.log) stem="${fname%.build.log}";;
*.img) stem="${fname%.img}";;
*.iso) stem="${fname%.iso}";;
*.raw) stem="${fname%.raw}";;
*) continue;;
esac
lang="${stem##*-}" # <lang> has no dashes, <descr> may
mkdir -p "./norm-artifacts/$lang"
cp "$file" "./norm-artifacts/$lang/$fname"
case "$fname" in
*.tree.tar.gz)
# unpacked on the server into <version>/<lang>/data/ for per-program downloads
cp "$file" "./tree-artifacts/$lang.tar.gz";;
*.sha256sums.txt)
cp "$file" "./norm-artifacts/$lang/sha256sums.txt";;
*.build.log)
cp "$file" "./norm-artifacts/$lang/build.log";;
*.img)
cp "$file" "./norm-artifacts/$lang/$fname"
# emulators (e.g. v86) hardcode <lang>/data/data/kolibri.img at the site root
mkdir -p "./stable-artifacts/$lang/data/data"
cp "$file" "./stable-artifacts/$lang/data/data/kolibri.img";;
*)
cp "$file" "./norm-artifacts/$lang/$fname";;
esac
done
# derive the version (git describe) from an artifact name:
# kolibrios-<descr>-<lang>.<ext> -> <descr>
sample="$(find ./norm-artifacts -type f -name 'kolibrios-*' | head -n1)"
# derive the version (git describe) from an artifact name: kolibrios-<descr>-<lang>.iso -> <descr>
sample="$(find ./norm-artifacts -type f -name 'kolibrios-*.iso' | head -n1)"
base="$(basename "${sample%.*}")" # kolibrios-<descr>-<lang>
version="${base%-*}" # kolibrios-<descr>
version="${version#kolibrios-}" # <descr>
echo "version=$version" >> $GITEA_OUTPUT
find ./norm-artifacts -type f -print
find ./norm-artifacts ./stable-artifacts ./tree-artifacts -type f -print
- name: Setup SSH
run: |
@@ -285,4 +344,6 @@ jobs:
-e "storage_path=${{ secrets.STORAGE_PATH }}" \
-e "version=${{ steps.normalize.outputs.version }}" \
-e "artifact_path=${{ gitea.workspace }}/norm-artifacts" \
-e "stable_artifact_path=${{ gitea.workspace }}/stable-artifacts" \
-e "tree_artifact_path=${{ gitea.workspace }}/tree-artifacts" \
-v
+1 -2
View File
@@ -34,11 +34,10 @@ jobs:
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.BOT_TOKEN }}
- name: Bump ${{ matrix.name }} and open PR
env:
TOKEN: ${{ secrets.BOT_TOKEN }}
TOKEN: ${{ secrets.GITEA_TOKEN }}
API: ${{ github.api_url }}
REPO: ${{ github.repository }}
NAME: ${{ matrix.name }}
+1 -1
View File
@@ -4,7 +4,7 @@
branch = main
[submodule "programs/develop/oberon07"]
path = programs/develop/oberon07
url = https://github.com/AntKrotov/oberon-07-compiler.git
url = https://git.kolibrios.org/KolibriOS/oberon-07-compiler.git
branch = master
[submodule "programs/cmm"]
path = programs/cmm
+12 -5
View File
@@ -74,7 +74,6 @@ if build_type == "ru_RU" then tup.append_table(img_files, {
{"WELCOME.HTM", VAR_DATA .. "/" .. build_type .. "/welcome.htm.kpack"},
{"EXAMPLE.ASM", SRC_PROGS .. "/develop/examples/example/rus/example.asm"},
{"DEVELOP/BACKY", SRC_PROGS .. "/develop/backy/Backy_ru"},
{"GAMES/BASEKURS.KLA", build_type .. "/games/basekurs.kla"},
{"File Managers/KFAR.INI", build_type .. "/File Managers/kfar.ini"},
{"GAMES/DESCENT", build_type .. "/games/descent"},
{"SETTINGS/.shell", SRC_PROGS .. "/system/shell/bin/rus/.shell"},
@@ -192,6 +191,12 @@ extra_files = {
{"kolibrios/develop/tcc/samples/", SRC_PROGS .. "/develop/ktcc/libc.obj/samples/*.sh"},
{"kolibrios/develop/tcc/samples/clayer/", SRC_PROGS .. "/develop/ktcc/libc.obj/samples/clayer/*"},
{"kolibrios/develop/utils/SPEDump", SRC_PROGS .. "/develop/SPEDump/SPEDump.kex"},
{"kolibrios/develop/XDPascal/", SRC_PROGS .. "/develop/XDPascal/xdpk/*"},
{"kolibrios/develop/XDPascal/projects2025/", SRC_PROGS .. "/develop/XDPascal/xdpk/projects2025/*"},
{"kolibrios/develop/XDPascal/projects2025/Compiler/", SRC_PROGS .. "/develop/XDPascal/xdpk/projects2025/Compiler/*"},
{"kolibrios/develop/XDPascal/projects2026/", SRC_PROGS .. "/develop/XDPascal/xdpk/projects2026/*"},
{"kolibrios/develop/XDPascal/source/", SRC_PROGS .. "/develop/XDPascal/xdpk/source/*"},
{"kolibrios/develop/XDPascal/units/", SRC_PROGS .. "/develop/XDPascal/xdpk/units/*"},
{"kolibrios/emul/", "common/emul/*"},
{"kolibrios/emul/dosbox/", "common/emul/DosBox/*"},
{"kolibrios/emul/e80/readme.txt", SRC_PROGS .. "/emulator/e80/readme.txt"},
@@ -291,8 +296,6 @@ extra_files = {
{"kolibrios/utils/vmode", "common/vmode"},
{"kolibrios/utils/texture", "common/utils/texture"},
{"kolibrios/utils/kterm/kterm", VAR_PROGS .. "/other/kterm/kterm"},
{"kolibrios/utils/kterm/serial.sys", VAR_DRVS .. "/serial/serial.sys"},
{"kolibrios/utils/kterm/install.sh", SRC .. "/drivers/serial/install.sh"},
{"kolibrios/utils/cnc_editor/cnc_editor", VAR_PROGS .. "/other/cnc_editor/cnc_editor"},
{"kolibrios/utils/cnc_editor/kolibri.NC", SRC_PROGS .. "/other/cnc_editor/kolibri.NC"},
{"kolibrios/utils/kfm/kfm.ini", "common/File Managers/kfm.ini"},
@@ -539,7 +542,7 @@ tup.append_table(img_files, {
{"NETWORK/PING", VAR_PROGS .. "/network/ping/ping"},
{"NETWORK/NETCFG", VAR_PROGS .. "/network/netcfg/netcfg"},
{"NETWORK/NETSTAT", VAR_PROGS .. "/network/netstat/netstat"},
{"NETWORK/NSINST", VAR_PROGS .. "/network/netsurf/nsinstall"},
{"NETWORK/NETSURF", VAR_PROGS .. "/network/netsurf/netsurf"},
{"NETWORK/NSLOOKUP", VAR_PROGS .. "/network/nslookup/nslookup"},
{"NETWORK/PASTA", VAR_PROGS .. "/network/pasta/pasta"},
{"NETWORK/SYNERGYC", VAR_PROGS .. "/network/synergyc/synergyc"},
@@ -570,12 +573,15 @@ tup.append_table(img_files, {
{"DRIVERS/UHCI.SYS", VAR_DRVS .. "/usb/uhci.sys"},
{"DRIVERS/OHCI.SYS", VAR_DRVS .. "/usb/ohci.sys"},
{"DRIVERS/EHCI.SYS", VAR_DRVS .. "/usb/ehci.sys"},
{"DRIVERS/XHCI.SYS", VAR_DRVS .. "/usb/xhci/xhci.sys"},
{"DRIVERS/USBHID.SYS", VAR_DRVS .. "/usb/usbhid/usbhid.sys"},
{"DRIVERS/USBFTDI.SYS", VAR_DRVS .. "/usb/usbftdi/usbftdi.sys"},
{"DRIVERS/USBOTHER.SYS",VAR_DRVS .. "/usb/usbother/usbother.sys"},
{"DRIVERS/USBCDC.SYS", VAR_DRVS .. "/usb/usbnet/usbcdc.sys"},
{"DRIVERS/USBRNDIS.SYS", VAR_DRVS .. "/usb/usbnet/usbrndis.sys"},
{"DRIVERS/USBSTOR.SYS", VAR_DRVS .. "/usb/usbstor.sys"},
{"DRIVERS/RDC.SYS", VAR_DRVS .. "/video/rdc.sys"},
{"DRIVERS/SERIAL.SYS", VAR_DRVS .. "/serial/serial.sys"},
{"DRIVERS/COMMOUSE.SYS", VAR_DRVS .. "/mouse/commouse.sys"},
{"DRIVERS/PS2MOUSE.SYS", VAR_DRVS .. "/mouse/ps2mouse4d/ps2mouse.sys"},
{"DRIVERS/TMPDISK.SYS", VAR_DRVS .. "/disk/tmpdisk.sys"},
@@ -649,7 +655,6 @@ tup.append_table(extra_files, {
})
-- For russian build, add russian-only programs.
if build_type == "ru_RU" then tup.append_table(img_files, {
{"GAMES/KLAVISHA", VAR_PROGS .. "/games/klavisha/klavisha"},
{"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_rus"},
}) else tup.append_table(img_files, {
{"DEVELOP/EXAMPLES/TESTCON2", VAR_PROGS .. "/develop/libraries/console_coff/examples/testcon2_eng"},
@@ -658,6 +663,8 @@ if build_type == "ru_RU" then tup.append_table(img_files, {
if build_type == "ru_RU" then tup.append_table(extra_files, {
{"kolibrios/utils/period", VAR_PROGS .. "/other/period/period"},
{"kolibrios/games/Dungeons/Dungeons", VAR_PROGS .. "/games/Dungeons/Dungeons"},
{"kolibrios/games/klavisha/klavisha", VAR_PROGS .. "/games/klavisha/klavisha"},
{"kolibrios/games/klavisha/basekurs.kla", "ru_RU/games/basekurs.kla"},
}) end
end -- tup.getconfig('NO_FASM') ~= 'full'
+1 -1
View File
@@ -48,7 +48,7 @@ mht=/sys/network/WebView
docx=/sys/network/WebView
url=/sys/network/WebView
fb2=/sys/fb2read
kla=/sys/games/klavisha
kla=/kolibrios/games/klavisha/klavisha
pdf=/kolibrios/media/updf
avi=/kolibrios/media/fplay_run
mpg=/kolibrios/media/fplay_run
Binary file not shown.
+1 -1
View File
@@ -179,7 +179,7 @@ stl=/sys/3d/view3ds
skn=/sys/skincfg
dtp=/sys/skincfg
lif=/kolibrios/demos/life2
kla=/sys/games/klavisha
kla=/kolibrios/games/klavisha/klavisha
pdf=/kolibrios/media/updf
smc=/kolibrios/emul/zsnes/zsnes
+1 -1
View File
@@ -39,7 +39,7 @@ Donkey=/kg/donkey
Loderunner=/kg/LRL/LRL,41
; 21days=/kg/21days,104 ;rus only
BabyPainter=/kg/BabyPainter,87
Klavisha=games/klavisha,69
Klavisha=/kg/klavisha/klavisha,69
Millioneer=/kg/WHOWTBAM/whowtbam,114
StarTrek71=/kg/sstartrek/SStarTrek
Descent=games/descent
+1 -1
View File
@@ -243,7 +243,7 @@ x=204
y=0
[22]
name=NETSURF
path=/sys/NETWORK/NSINST
path=/sys/NETWORK/NETSURF
param=
ico=125
x=204
+1
View File
@@ -116,6 +116,7 @@
33 HTTPGet |network/httpget
33 Downloader |network/dl
12 WebView Browser |network/webview
12 NetSurf |network/netsurf
#13 **** SERVERS
24 FTP |network/ftpd
#14 **** OTHER
+1 -1
View File
@@ -243,7 +243,7 @@ x=204
y=0
[22]
name=NETSURF
path=/sys/NETWORK/NSINST
path=/sys/NETWORK/NETSURF
param=
ico=125
x=204
+1
View File
@@ -121,6 +121,7 @@
16 HTTPGet |network/httpget
16 Descargas |network/dl
16 Navegador WebView |network/webview
12 NetSurf |network/netsurf
#15 **** OTROS
16 Reloj analвgico |demos/aclock
16 Reloj binario |demos/bcdclk
+1 -1
View File
@@ -39,7 +39,7 @@ docx=/sys/network/WebView
url=/sys/network/WebView
fb2=/sys/fb2read
mht=/sys/network/WebView
kla=/sys/games/klavisha
kla=/kolibrios/games/klavisha/klavisha
pdf=/kolibrios/media/updf
avi=/kolibrios/media/fplay_run
mpg=/kolibrios/media/fplay_run
+1 -1
View File
@@ -39,7 +39,7 @@ Donkey=/kg/donkey
Loderunner=/kg/LRL/LRL,41
21days=/kg/21days,104 ;rus only
BabyPainter=/kg/BabyPainter,87
Klavisha=games/klavisha,69
Klavisha=/kg/klavisha/klavisha,69
Millioneer=/kg/WHOWTBAM/whowtbam,114
StarTrek71=/kg/sstartrek/SStarTrek
Descent=games/descent
+1 -1
View File
@@ -243,7 +243,7 @@ x=204
y=0
[22]
name=NETSURF
path=/sys/NETWORK/NSINST
path=/sys/NETWORK/NETSURF
param=
ico=125
x=204
+2 -1
View File
@@ -115,6 +115,7 @@
33 HTTPGet |network/httpget
33 Загрузчик |network/dl
12 Браузер WebView |network/webview
12 Браузер NetSurf |network/netsurf
#14 **** Разное
00 Эмуляторы* > |@6
45 Создание скриншотов |scrshoot
@@ -122,7 +123,7 @@
18 FB2 Читалка |fb2read
16 Аналоговые часы |aclock
21 Таблица Менделеева |/kolibrios/utils/period
59 Тренажёр KJ|ABuIIIA |games/klavisha
59 Тренажёр KJIABuIIIA |/kolibrios/games/klavisha/klavisha
16 Бинарные часы |demos/bcdclk
53 Таймер |timer
09 Разархиватор Unz |unz
+11 -13
View File
@@ -515,20 +515,18 @@ HDA_AMP_VOLMASK equ 0x7F
; unsolicited event handler
HDA_UNSOL_QUEUE_SIZE equ 64
HDA_UNSOL_QUEUE_SIZE equ 64 ; must stay a power of 2 (used as a bitmask for wrap)
;struc HDA_BUS_UNSOLICITED
;{
; ; ring buffer
; .queue:
; times HDA_UNSOL_QUEUE_SIZE*2 dd ?
; .rp dd ?
; .wp dd ?
;
; ; workqueue
; .work dd ?;struct work_struct work;
; .bus dd ? ;struct hda_bus ;bus
;};
struc HDA_BUS_UNSOLICITED
{
; ring buffer
.queue rd HDA_UNSOL_QUEUE_SIZE * 2 ; 2 dword for each event (res and res_ex)
.rp dd ? ; Read pointer
.wp dd ? ; Write pointer
; ; workqueue
; .work dd ? ;struct work_struct work;
; .bus dd ? ;struct hda_bus ;bus
}
; Helper for automatic ping configuration
AUTO_PIN_MIC equ 0
+68 -19
View File
@@ -654,7 +654,15 @@ end if
stdcall hda_codec_setup_stream, eax, SDO_TAG, 0, 0x11 ; Left & Right channels (Back panel)
;Asper+ ]
invoke TimerHS, 1, 0, snd_hda_automute, 0
if USE_UNSOL_EV = 0
invoke TimerHS, 1, 0, snd_hda_automute, 1
else
; Keep the unsolicited-event mode on the event-driven path. Running
; snd_hda_automute at startup can issue codec commands before the new
; unsolicited-response flow is ready, which hangs some systems.
invoke TimerHS, 1, 0, process_unsol_events, 0
end if
if USE_SINGLE_MODE
mov esi, msgSingleMode
invoke SysMsgBoardStr
@@ -2635,7 +2643,7 @@ proc snd_hda_automute stdcall, data:dword
test eax, eax
jz .out
stdcall snd_hda_read_pin_sense, edx, 1
stdcall snd_hda_read_pin_sense, edx, [data]
test eax, AC_PINSENSE_PRESENCE
jnz @f
xchg ecx, esi
@@ -2664,24 +2672,64 @@ proc snd_hda_automute stdcall, data:dword
endp
;Asper remember to add this functions:
proc snd_hda_queue_unsol_event stdcall, par1:dword, par2:dword
;if DEBUG
; push esi
; mov esi, msgUnsolEvent
; invoke SysMsgBoardStr
; pop esi
;end if
if USE_UNSOL_EV = 1
;Test. Do not make queue, process immediately!
;stdcall here snd_hda_read_pin_sense stdcall, nid:dword, trigger_sense:dword
;and then mute/unmute pin based on the results
invoke TimerHS, 1, 0, snd_hda_automute, 0
end if
ret
endp
;...
; ;Asper remember to add this functions:
; proc snd_hda_queue_unsol_event stdcall, par1:dword, par2:dword
; ;if DEBUG
; ; push esi
; ; mov esi, msgUnsolEvent
; ; invoke SysMsgBoardStr
; ; pop esi
; ;end if
; if USE_UNSOL_EV = 1
; ;Test. Do not make queue, process immediately!
; ;stdcall here snd_hda_read_pin_sense stdcall, nid:dword, trigger_sense:dword
; ;and then mute/unmute pin based on the results
; invoke TimerHS, 1, 0, snd_hda_automute, 0
; end if
; ret
; endp
; ;...
align 4
proc snd_hda_queue_unsol_event stdcall, res:dword, res_ex:dword
; Single-producer (HDA IRQ) lock-free enqueue. The caller azx_update_rirb
; only carries EBX across iterations and reloads the rest, and TimerHS
; preserves EBX too - so by using scratch regs only we need no saves.
mov eax, [unsol_events.wp]
lea edx, [eax+1]
and edx, HDA_UNSOL_QUEUE_SIZE - 1 ; next write pos (size must be 2^n)
cmp edx, [unsol_events.rp]
je .full ; ring full -> drop, keep 1 slot free
mov ecx, [res]
mov [unsol_events.queue + eax*8], ecx
mov ecx, [res_ex]
mov [unsol_events.queue + eax*8 + 4], ecx
mov [unsol_events.wp], edx ; publish only after data is stored
invoke TimerHS, 1, 0, process_unsol_events, 0
.full:
ret
endp
align 4
proc process_unsol_events stdcall, data:dword
; Runs from TimerHS (single consumer). Uses only EAX (scratch) and calls
; snd_hda_automute, which preserves every register, so nothing is saved.
.loop:
mov eax, [unsol_events.rp]
cmp eax, [unsol_events.wp]
je .done
; The event payload is at [unsol_events.queue + eax*8] (res) and +4 (res_ex).
; Per-pin tag parsing is not implemented yet, so just re-evaluate jack state.
inc eax
and eax, HDA_UNSOL_QUEUE_SIZE - 1
mov [unsol_events.rp], eax
stdcall snd_hda_automute, 0
jmp .loop
.done:
ret
endp
align 4
proc fdword2str stdcall, flags:dword ; bit 0 - skipLeadZeroes; bit 1 - newLine; other bits undefined
@@ -3057,6 +3105,7 @@ aspinlock dd SPINLOCK_FREE
codec CODEC
ctrl AC_CNTRL
unsol_events HDA_BUS_UNSOLICITED
;Asper: BDL must be aligned to 128 according to HDA specification.
pcmout_bdl rd 1
+59 -5
View File
@@ -1,4 +1,4 @@
SERIAL_COMPATIBLE_API_VER = 0 ; increments in case of breaking changes
SERIAL_COMPATIBLE_API_VER = 1 ; increments in case of breaking changes
SERIAL_API_GET_VERSION = 0
SERIAL_API_SRV_ADD_PORT = 1
@@ -9,6 +9,7 @@ SERIAL_API_CLOSE_PORT = 5
SERIAL_API_SETUP_PORT = 6
SERIAL_API_READ = 7
SERIAL_API_WRITE = 8
SERIAL_API_ENUM_PORTS = 9
SERIAL_API_ERR_PORT_INVALID = 1
SERIAL_API_ERR_PORT_BUSY = 2
@@ -29,6 +30,9 @@ SERIAL_CONF_STOP_BITS_2 = 2
SERIAL_CONF_FLOW_CTRL_NONE = 0
SERIAL_INFO_DRIVER_LEN = 16
SERIAL_INFO_DESCR_LEN = 64
struct SP_DRIVER
size dd ? ; size of this struct
startup dd ? ; int __stdcall (*startup)(void *drv_data, const struct serial_conf *conf);
@@ -46,7 +50,20 @@ struct SP_CONF
flow_ctrl db ?
ends
proc serial_add_port stdcall, drv:dword, drv_data:dword
struct SP_PORT_INFO
size dd ? ; size of this struct
driver dd ? ; ASCIIZ driver name, e.g. "uart16550", "usb-cdc"
descr dd ? ; ASCIIZ description, may be NULL
ends
struct SP_PORT_ENUM_ENTRY
id dd ? ; unique port number (SERIAL_PORT.id)
busy dd ? ; 0 = free, non-zero = port is opened
driver rb SERIAL_INFO_DRIVER_LEN
descr rb SERIAL_INFO_DESCR_LEN
ends
proc serial_add_port stdcall, drv:dword, drv_data:dword, info:dword
locals
handler dd ?
io_code dd ?
@@ -60,7 +77,7 @@ endl
mov [io_code], SERIAL_API_SRV_ADD_PORT
lea eax, [drv]
mov [input], eax
mov [inp_size], 8
mov [inp_size], 12
xor eax, eax
mov [output], eax
mov [out_size], eax
@@ -129,7 +146,7 @@ proc serial_port_init
ret
endp
proc serial_port_get_version stdcall, version:dword
proc serial_port_get_version stdcall uses ebx, version:dword
locals
.handler dd ?
.io_code dd ?
@@ -149,7 +166,7 @@ endl
lea ecx, [.handler]
mcall SF_SYS_MISC, SSF_CONTROL_DRIVER
ret
endp
@@ -297,6 +314,43 @@ endl
ret
endp
proc serial_port_enum stdcall uses ebx, buf:dword, buf_size:dword, \
total:dword, filled:dword
locals
.handler dd ?
.io_code dd ?
.input dd ?
.inp_size dd ?
.output dd ?
.out_size dd ?
endl
push [buf_size]
push [buf]
mov eax, [serial_drv_handle]
mov [.handler], eax
mov dword [.io_code], SERIAL_API_ENUM_PORTS
mov [.input], esp
mov dword [.inp_size], 8
sub esp, 8
mov [.output], esp
mov dword [.out_size], 8
lea ecx, [.handler]
mcall SF_SYS_MISC, SSF_CONTROL_DRIVER
pop ebx edx
cmp eax, -1
je .err
mov ecx, [total]
mov [ecx], ebx
mov ecx, [filled]
mov [ecx], edx
.err:
add esp, 8
ret
endp
align 4
serial_drv_name db "SERIAL", 0
serial_drv_handle dd ?
-5
View File
@@ -1,5 +0,0 @@
#SHS
echo Installing serial driver for kterm...
cp /kolibrios/utils/kterm/serial.sys /sys/drivers/
/sys/loaddrv serial
echo Serial driver successfully installed!
+148 -7
View File
@@ -44,6 +44,8 @@ struct SERIAL_PORT
rx_buf RING_BUF
tx_buf RING_BUF
conf SP_CONF
driver rb SERIAL_INFO_DRIVER_LEN ; ASCIIZ, copied from SP_PORT_INFO.driver in add_port
descr rb SERIAL_INFO_DESCR_LEN ; ASCIIZ, copied from SP_PORT_INFO.descr in add_port (may be empty)
ends
proc START c, reason:dword, cmdline:dword
@@ -57,7 +59,7 @@ proc START c, reason:dword, cmdline:dword
stdcall uart_probe, 0x2f8, 3
stdcall uart_probe, 0x3e8, 4
stdcall uart_probe, 0x2e8, 3
invoke RegService, drv_name, service_proc
invoke RegService, serial_drv_name, service_proc
ret
.fail:
@@ -75,7 +77,7 @@ srv_calls:
dd service_proc.setup
dd service_proc.read
dd service_proc.write
; TODO enumeration
dd service_proc.enum_ports
srv_calls_end:
proc service_proc stdcall uses ebx esi edi, ioctl:dword
@@ -97,11 +99,13 @@ proc service_proc stdcall uses ebx esi edi, ioctl:dword
; in:
; +0: driver
; +4: driver data
cmp [edx + IOCTL.inp_size], 8
; +8: port info (SP_PORT_INFO*)
cmp [edx + IOCTL.inp_size], 12
jb .err
mov ebx, [edx + IOCTL.input]
mov ecx, [ebx]
mov edx, [ebx + 4]
mov ebx, [ebx + 8]
call add_port
ret
@@ -137,6 +141,7 @@ proc service_proc stdcall uses ebx esi edi, ioctl:dword
; +4 addr to SERIAL_CONF
; out:
; +0 port handle if success
; eax = 0 if success, otherwise an error code SERIAL_API_ERR_*
cmp [edx + IOCTL.inp_size], 8
jb .err
cmp [edx + IOCTL.out_size], 4
@@ -220,25 +225,60 @@ proc service_proc stdcall uses ebx esi edi, ioctl:dword
mov [ebx], ecx
ret
.enum_ports:
; in:
; +0 output buffer (array of SP_PORT_ENUM_ENTRY), may be NULL
; +4 output buffer size in bytes
; out:
; +0 total number of ports in the system
; +4 number of entries actually filled into the buffer
; eax = 0 if success, -1 otherwise
cmp [edx + IOCTL.inp_size], 8
jb .err
cmp [edx + IOCTL.out_size], 8
jb .err
mov ebx, [edx + IOCTL.input]
push edx
mov eax, [ebx]
mov edx, [ebx + 4]
call sp_enum
pop edx
mov ebx, [edx + IOCTL.output]
mov [ebx], eax
mov [ebx + 4], ecx
xor eax, eax
ret
.err:
or eax, -1
ret
endp
; struct SERIAL_PORT __fastcall *add_port(const struct SP_DRIVER *drv, const void *drv_data);
align 4
; @param ecx pointer to SP_DRIVER
; @param edx driver-specific argument
; @param ebx pointer to SP_PORT_INFO
; @return SERIAL_PORT descriptor
proc add_port uses edi
DEBUGF L_DBG, "serial.sys: add port drv=%x drv_data=%x\n", ecx, edx
DEBUGF L_DBG, "serial.sys: add port drv=%x drv_data=%x info=%x\n", ecx, edx, ebx
mov eax, [ecx + SP_DRIVER.size]
cmp eax, sizeof.SP_DRIVER
jne .fail
test ebx, ebx
jz .fail
mov eax, [ebx + SP_PORT_INFO.size]
cmp eax, sizeof.SP_PORT_INFO
jne .fail
; alloc memory for serial port descriptor
push ecx
push edx
push ebx
movi eax, sizeof.SERIAL_PORT
invoke Kmalloc
pop ebx
pop edx
pop ecx
test eax, eax
@@ -252,6 +292,17 @@ proc add_port uses edi
invoke MutexInit
and [edi + SERIAL_PORT.con], 0
; copy port info strings
mov eax, [ebx + SP_PORT_INFO.driver]
lea edx, [edi + SERIAL_PORT.driver]
mov ecx, SERIAL_INFO_DRIVER_LEN
call copy_bounded_str
mov eax, [ebx + SP_PORT_INFO.descr]
lea edx, [edi + SERIAL_PORT.descr]
mov ecx, SERIAL_INFO_DESCR_LEN
call copy_bounded_str
mov ecx, port_list_mutex
invoke MutexLock
@@ -282,7 +333,35 @@ proc add_port uses edi
endp
align 4
; u32 __fastcall *remove_port(struct SERIAL_PORT *port);
; copies an ASCIIZ string into a fixed-size buffer: copies up to (size - 1)
; bytes or until the NUL, then zero-pads the rest of the buffer
; @param eax source ASCIIZ ptr, may be NULL
; @param edx dest buffer ptr
; @param ecx dest buffer size in bytes, must be >= 1
proc copy_bounded_str uses esi edi
mov esi, eax
mov edi, edx
dec ecx ; reserve the last byte for the NUL terminator
.copy:
test ecx, ecx
jz .pad
test esi, esi
jz .pad
lodsb
test al, al
jz .pad
stosb
dec ecx
jmp .copy
.pad:
inc ecx ; account for the reserved NUL byte
xor al, al
rep stosb
ret
endp
align 4
; @param ecx serial port descriptor
proc remove_port uses esi
mov esi, ecx
mov ecx, port_list_mutex
@@ -657,7 +736,69 @@ proc sp_write
ret
endp
drv_name db 'SERIAL', 0
align 4
; @param eax buf
; @param edx buf_size (bytes)
; @return eax total port count in the system
; ecx entries filled into buf
proc sp_enum uses ebx esi edi
mov ecx, eax
mov eax, edx
xor edx, edx
mov ebx, sizeof.SP_PORT_ENUM_ENTRY
div ebx
; eax max entries count
mov edi, ecx
imul eax, sizeof.SP_PORT_ENUM_ENTRY
add eax, ecx
mov edx, eax ; end-of-buffer boundary
xor ebx, ebx ; total port count
xor ecx, ecx ; filled count
push ecx edx
mov ecx, port_list_mutex
invoke MutexLock
pop edx ecx
mov esi, port_list
.next:
mov esi, [esi + SERIAL_PORT.fd]
cmp esi, port_list
jz .done
inc ebx
cmp edi, edx
jae .next
mov eax, [esi + SERIAL_PORT.id]
mov [edi + SP_PORT_ENUM_ENTRY.id], eax
xor eax, eax
cmp dword [esi + SERIAL_PORT.con], 0
setnz al
mov [edi + SP_PORT_ENUM_ENTRY.busy], eax
push ecx esi edi
lea esi, [esi + SERIAL_PORT.driver]
lea edi, [edi + SP_PORT_ENUM_ENTRY.driver]
mov ecx, (SERIAL_INFO_DRIVER_LEN + SERIAL_INFO_DESCR_LEN) / 4
rep movsd
pop edi esi ecx
add edi, sizeof.SP_PORT_ENUM_ENTRY
inc ecx
jmp .next
.done:
push ecx
mov ecx, port_list_mutex
invoke MutexUnlock
pop ecx
mov eax, ebx
ret
endp
include_debug_strings
align 4
+9
View File
@@ -169,6 +169,7 @@ proc uart_probe stdcall uses ebx esi edi, io_addr:dword, irqn:dword
; register port
lea ecx, [uart_drv]
mov edx, edi
lea ebx, [uart_port_info]
call add_port
test eax, eax
jz .free_desc ; TODO detach_int_handler?
@@ -406,3 +407,11 @@ uart_drv:
dd uart_reconf
dd uart_tx
uart_drv_end:
align 4
uart_port_info:
dd uart_port_end - uart_port_info
dd uart_port_name
dd 0
uart_port_end:
uart_port_name db 'uart16550', 0
+203 -310
View File
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2026. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; FTDI chips driver for KolibriOS ;;
@@ -15,10 +15,11 @@
format PE DLL native 0.05
entry START
DEBUG = 1
L_DBG = 1
L_ERR = 2
__DEBUG__ = 1
__DEBUG_LEVEL__ = 1
__DEBUG_LEVEL__ = L_ERR
node equ ftdi_context
node.next equ ftdi_context.next_context
@@ -122,9 +123,10 @@ TYPE_232H=6
TYPE_230X=7
;strings
my_driver db 'usbother',0
my_driver db 'usbftdi',0
serial_driver db 'SERIAL',0
nomemory_msg db 'K : no memory',13,10,0
nomemory_msg db 'ftdi: no memory',13,10,0
ftdi_port_name db 'ftdi',0
; Structures
struct ftdi_context
@@ -200,10 +202,13 @@ endp
proc AddDevice stdcall uses ebx esi edi, .config_pipe:DWORD, .config_descr:DWORD, .interface:DWORD
locals
.pinfo rb sizeof.SP_PORT_INFO
endl
invoke USBGetParam, [.config_pipe], 0
mov edx, eax
DEBUGF 2,'K : Detected device vendor: 0x%x\n', [eax+usb_descr.idVendor]
DEBUGF L_DBG, 'ftdi: Detected device vendor: 0x%x\n', [eax+usb_descr.idVendor]
cmp word[eax+usb_descr.idVendor], 0x0403
jnz .notftdi
mov eax, sizeof.ftdi_context
@@ -214,7 +219,7 @@ proc AddDevice stdcall uses ebx esi edi, .config_pipe:DWORD, .config_descr:DWORD
invoke SysMsgBoardStr
jmp .nothing
@@:
DEBUGF 2,'K : Adding struct to list 0x%x\n', eax
DEBUGF L_DBG, 'ftdi: Adding struct to list 0x%x\n', eax
call linkedlist_add
mov ebx, [.config_pipe]
@@ -233,7 +238,7 @@ proc AddDevice stdcall uses ebx esi edi, .config_pipe:DWORD, .config_descr:DWORD
jmp .slow
mov cx, [edx+usb_descr.bcdDevice]
DEBUGF 2, 'K : Chip type 0x%x\n', ecx
DEBUGF L_DBG, 'ftdi: Chip type 0x%x\n', ecx
cmp cx, 0x400
jnz @f
mov [eax + ftdi_context.chipType], TYPE_BM
@@ -287,8 +292,13 @@ proc AddDevice stdcall uses ebx esi edi, .config_pipe:DWORD, .config_descr:DWORD
mov eax, [serial_drv_entry]
test eax, eax
jz @f
stdcall serial_add_port, uart_drv, ebx
DEBUGF 1, "usbftdi: add serial port with result %x\n", eax
mov dword [.pinfo + SP_PORT_INFO.size], sizeof.SP_PORT_INFO
mov dword [.pinfo + SP_PORT_INFO.driver], ftdi_port_name
; TODO obtain iManufacturer, iProduct and iSerial strings
mov dword [.pinfo + SP_PORT_INFO.descr], 0
lea ecx, [.pinfo]
stdcall serial_add_port, uart_drv, ebx, ecx
DEBUGF L_DBG, 'ftdi: add serial port with result %x\n', eax
@@:
mov [ebx + ftdi_context.port_handle], eax
@@ -296,7 +306,7 @@ proc AddDevice stdcall uses ebx esi edi, .config_pipe:DWORD, .config_descr:DWORD
ret
.notftdi:
DEBUGF 1,'K : Skipping not FTDI device\n'
DEBUGF L_DBG, 'ftdi: Skipping not FTDI device\n'
.nothing:
xor eax, eax
ret
@@ -317,7 +327,7 @@ EventData rd 3
endl
mov edi, [ioctl]
mov eax, [edi+io_code]
DEBUGF 1,'K : FTDI got the request: %d\n', eax
DEBUGF L_DBG, 'ftdi: FTDI got the request: %d\n', eax
test eax, eax ;0
jz .version
dec eax ;1
@@ -416,7 +426,7 @@ endl
.version:
jmp .endswitch
.error:
DEBUGF 1, 'K : FTDI error occured! %d\n', eax
DEBUGF L_ERR, 'ftdi: error occured! %d\n', eax
;mov esi, [edi+output]
;mov [esi], dword 'ERR0'
;or [esi], eax
@@ -449,7 +459,7 @@ endl
mov word[ConfPacket+6], cx
.own_index:
mov ebx, [edi+4]
DEBUGF 2,'K : ConfPacket 0x%x 0x%x\n', [ConfPacket], [ConfPacket+4]
DEBUGF L_DBG, 'ftdi: ConfPacket 0x%x 0x%x\n', [ConfPacket], [ConfPacket+4]
lea esi, [ConfPacket]
lea edi, [EventData]
invoke USBControlTransferAsync, [ebx + ftdi_context.nullP], esi, 0,\
@@ -465,7 +475,7 @@ endl
jmp .error
.ftdi_setrtshigh:
DEBUGF 2,'K : FTDI Setting RTS pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Setting RTS pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
@@ -473,7 +483,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_setrtslow:
DEBUGF 2,'K : FTDI Setting RTS pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Setting RTS pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
@@ -481,7 +491,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_setdtrhigh:
DEBUGF 2,'K : FTDI Setting DTR pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Setting DTR pin HIGH PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
@@ -489,7 +499,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_setdtrlow:
DEBUGF 2,'K : FTDI Setting DTR pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Setting DTR pin LOW PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_MODEM_CTRL_REQUEST shl 8) \
@@ -497,7 +507,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_usb_reset:
DEBUGF 2,'K : FTDI Reseting PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Reseting PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_RESET_REQUEST shl 8) \
@@ -505,7 +515,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_purge_rx_buf:
DEBUGF 2, 'K : FTDI Purge TX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Purge TX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_RESET_REQUEST shl 8) \
@@ -513,7 +523,7 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_purge_tx_buf:
DEBUGF 2, 'K : FTDI Purge RX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Purge RX buffer PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_RESET_REQUEST shl 8) \
@@ -521,42 +531,42 @@ endl
jmp .ftdi_out_control_transfer_noinp
.ftdi_set_bitmode:
DEBUGF 2, 'K : FTDI Set bitmode 0x%x, bitmask 0x%x %d PID: %d Dev handler 0x0x%x\n', \
DEBUGF L_DBG, 'ftdi: Set bitmode 0x%x, bitmask 0x%x %d PID: %d Dev handler 0x0x%x\n', \
[edi+8]:2,[edi+10]:2,[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_BITMODE_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_set_line_property:
DEBUGF 2, 'K : FTDI Set line property 0x%x PID: %d Dev handler 0x0x%x\n', \
DEBUGF L_DBG, 'ftdi: Set line property 0x%x PID: %d Dev handler 0x0x%x\n', \
[edi+8]:4,[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_DATA_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_set_latency_timer:
DEBUGF 2, 'K : FTDI Set latency %d PID: %d Dev handler 0x0x%x\n', \
DEBUGF L_DBG, 'ftdi: Set latency %d PID: %d Dev handler 0x0x%x\n', \
[edi+8],[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_LATENCY_TIMER_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_set_event_char:
DEBUGF 2, 'K : FTDI Set event char %c PID: %d Dev handler 0x0x%x\n', \
DEBUGF L_DBG, 'ftdi: Set event char %c PID: %d Dev handler 0x0x%x\n', \
[edi+8],[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_EVENT_CHAR_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_set_error_char:
DEBUGF 2, 'K : FTDI Set error char %c PID: %d Dev handler 0x0x%x\n', \
DEBUGF L_DBG, 'ftdi: Set error char %c PID: %d Dev handler 0x0x%x\n', \
[edi+8],[edi],[edi+4]
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_ERROR_CHAR_REQUEST shl 8)
jmp .ftdi_out_control_transfer_withinp
.ftdi_setflowctrl:
DEBUGF 2, 'K : FTDI Set flow control PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Set flow control PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_FLOW_CTRL_REQUEST shl 8) + (0 shl 16)
@@ -569,7 +579,7 @@ endl
jmp .own_index
.ftdi_read_pins:
DEBUGF 2, 'K : FTDI Read pins PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Read pins PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov ebx, [edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_IN_REQTYPE) \
@@ -598,7 +608,7 @@ endl
jmp .error
.ftdi_set_wchunksize:
DEBUGF 2, 'K : FTDI Set write chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
DEBUGF L_DBG, 'ftdi: Set write chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
[edi+8], [edi], [edi+4]
mov ebx, [edi+4]
mov ecx, [edi+8]
@@ -608,7 +618,7 @@ endl
jmp .endswitch
.ftdi_get_wchunksize:
DEBUGF 2, 'K : FTDI Get write chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Get write chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov esi, [edi+output]
mov edi, [edi+input]
@@ -618,7 +628,7 @@ endl
jmp .endswitch
.ftdi_set_rchunksize:
DEBUGF 2, 'K : FTDI Set read chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
DEBUGF L_DBG, 'ftdi: Set read chunksize %d bytes PID: %d Dev handler 0x0x%x\n', \
[edi+8], [edi], [edi+4]
mov ebx, [edi+4]
mov ecx, [edi+8]
@@ -628,7 +638,7 @@ endl
jmp .endswitch
.ftdi_get_rchunksize:
DEBUGF 2, 'K : FTDI Get read chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Get read chunksize PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov esi, [edi+output]
mov edi, [edi+input]
@@ -638,7 +648,7 @@ endl
jmp .endswitch
.ftdi_write_data:
DEBUGF 2, 'K : FTDI Write %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
DEBUGF L_DBG, 'ftdi: Write %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
[edi], [edi+4]
mov esi, edi
add esi, 12
@@ -685,7 +695,7 @@ endl
jmp .write_loop
.ftdi_read_data:
DEBUGF 2, 'K : FTDI Read %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
DEBUGF L_DBG, 'ftdi: Read %d bytes PID: %d Dev handler 0x%x\n', [edi+8],\
[edi], [edi+4]
mov edi, [ioctl]
mov esi, [edi+input]
@@ -743,7 +753,7 @@ endl
;---Dirty hack end
.ftdi_poll_modem_status:
DEBUGF 2, 'K : FTDI Poll modem status PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Poll modem status PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov ebx, [edi+4]
mov dword[ConfPacket], (FTDI_DEVICE_IN_REQTYPE) \
@@ -767,7 +777,7 @@ endl
jmp .endswitch
.ftdi_get_latency_timer:
DEBUGF 2, 'K : FTDI Get latency timer PID: %d Dev handler 0x0x%x\n', [edi],\
DEBUGF L_DBG, 'ftdi: Get latency timer PID: %d Dev handler 0x0x%x\n', [edi],\
[edi+4]
mov ebx, [edi+4]
mov dword[ConfPacket], FTDI_DEVICE_IN_REQTYPE \
@@ -787,7 +797,7 @@ endl
jmp .endswitch
.ftdi_get_list:
DEBUGF 2, 'K : FTDI devices list request\n'
DEBUGF L_DBG, 'ftdi: devices list request\n'
mov edi, [edi+output]
xor ecx, ecx
call linkedlist_gethead
@@ -817,7 +827,7 @@ endl
jmp .endswitch
.ftdi_lock:
DEBUGF 2, 'K : FTDI Lock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
DEBUGF L_DBG, 'ftdi: Lock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
mov esi, [edi+input]
mov ebx, [esi+4]
mov eax, [ebx + ftdi_context.lockPID]
@@ -831,7 +841,7 @@ endl
jmp .endswitch
.ftdi_unlock:
DEBUGF 2, 'K : FTDI Unlock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
DEBUGF L_DBG, 'ftdi: Unlock PID: %d Dev handler 0x0x%x\n', [edi], [edi+4]
mov esi, [edi+input]
mov edi, [edi+output]
mov ebx, [esi+4]
@@ -845,145 +855,19 @@ endl
mov [edi], eax
jmp .endswitch
H_CLK = 120000000
C_CLK = 48000000
.ftdi_set_baudrate:
DEBUGF 2, 'K : FTDI Set baudrate to %d PID: %d Dev handle: 0x%x\n',\
DEBUGF L_DBG, 'ftdi: Set baudrate to %d PID: %d Dev handle: 0x%x\n',\
[edi+8], [edi], [edi+4]
mov ebx, [edi+4]
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jl .c_clk
imul eax, [edi+8], 10
cmp eax, H_CLK / 0x3FFF
jle .c_clk
.h_clk:
cmp dword[edi+8], H_CLK/10
jl .h_nextbaud1
xor edx, edx
mov ecx, H_CLK/10
jmp .calcend
.c_clk:
cmp dword[edi+8], C_CLK/16
jl .c_nextbaud1
xor edx, edx
mov ecx, C_CLK/16
jmp .calcend
.h_nextbaud1:
cmp dword[edi+8], H_CLK/(10 + 10/2)
jl .h_nextbaud2
mov edx, 1
mov ecx, H_CLK/(10 + 10/2)
jmp .calcend
.c_nextbaud1:
cmp dword[edi+8], C_CLK/(16 + 16/2)
jl .c_nextbaud2
mov edx, 1
mov ecx, C_CLK/(16 + 16/2)
jmp .calcend
.h_nextbaud2:
cmp dword[edi+8], H_CLK/(2*10)
jl .h_nextbaud3
mov edx, 2
mov ecx, H_CLK/(2*10)
jmp .calcend
.c_nextbaud2:
cmp dword[edi+8], C_CLK/(2*16)
jl .c_nextbaud3
mov edx, 2
mov ecx, C_CLK/(2*16)
jmp .calcend
.h_nextbaud3:
mov eax, H_CLK*16/10 ; eax - best_divisor
xor edx, edx
div dword[edi+8] ; [edi+8] - baudrate
push eax
and eax, 1
pop eax
shr eax, 1
jz .h_rounddowndiv ; jump by result of and eax, 1
inc eax
.h_rounddowndiv:
cmp eax, 0x20000
jle .h_best_divok
mov eax, 0x1FFFF
.h_best_divok:
mov ecx, eax
mov eax, H_CLK*16/10
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jz .rounddownbaud
inc ecx
jmp .rounddownbaud
.c_nextbaud3:
mov eax, C_CLK ; eax - best_divisor
xor edx, edx
div dword[edi+8] ; [edi+8] - baudrate
push eax
and eax, 1
pop eax
shr eax, 1
jnz .c_rounddowndiv ; jump by result of and eax, 1
inc eax
.c_rounddowndiv:
cmp eax, 0x20000
jle .c_best_divok
mov eax, 0x1FFFF
.c_best_divok:
mov ecx, eax
mov eax, C_CLK
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jnz .rounddownbaud
inc ecx
.rounddownbaud:
mov edx, eax ; edx - encoded_divisor
shr edx, 3
and eax, 0x7
push 7 6 5 1 4 2 3 0
mov eax, [esp+eax*4]
shl eax, 14
or edx, eax
add esp, 32
.calcend:
mov eax, edx ; eax - *value
mov ecx, edx ; ecx - *index
and eax, 0xFFFF
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jge .foxyindex
shr ecx, 16
jmp .preparepacket
.foxyindex:
shr ecx, 8
and ecx, 0xFF00
or ecx, [ebx + ftdi_context.index]
.preparepacket:
mov esi, [edi+8]
call ftdi_calc_baud_divisor
mov word[ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_BAUDRATE_REQUEST shl 8)
mov word[ConfPacket+2], ax
mov word[ConfPacket+4], cx
mov word[ConfPacket+6], 0
jmp .own_index
jmp .own_index
endp
restore handle
restore io_code
@@ -993,10 +877,143 @@ restore output
restore out_size
proc ftdi_calc_baud_divisor
; in: ebx = ftdi_context pointer
; esi = baud rate
; out: ax = encoded value
; cx = encoded index
; destroys: eax, ecx, edx, esi
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jl .c_clk
imul eax, esi, 10
cmp eax, H_CLK / 0x3FFF
jle .c_clk
.h_clk:
cmp esi, H_CLK / 10
jl .h_nextbaud1
xor edx, edx
mov ecx, H_CLK / 10
jmp .calcend
.c_clk:
cmp esi, C_CLK / 16
jl .c_nextbaud1
xor edx, edx
mov ecx, C_CLK / 16
jmp .calcend
.h_nextbaud1:
cmp esi, H_CLK / (10 + 10 / 2)
jl .h_nextbaud2
mov edx, 1
mov ecx, H_CLK / (10 + 10 / 2)
jmp .calcend
.c_nextbaud1:
cmp esi, C_CLK / (16 + 16 / 2)
jl .c_nextbaud2
mov edx, 1
mov ecx, C_CLK/(16 + 16 / 2)
jmp .calcend
.h_nextbaud2:
cmp esi, H_CLK / (2 * 10)
jl .h_nextbaud3
mov edx, 2
mov ecx, H_CLK / (2 * 10)
jmp .calcend
.c_nextbaud2:
cmp esi, C_CLK / (2 * 16)
jl .c_nextbaud3
mov edx, 2
mov ecx, C_CLK / (2 * 16)
jmp .calcend
.h_nextbaud3:
mov eax, H_CLK * 16 / 10 ; eax - best_divisor
xor edx, edx
div esi
push eax
and eax, 1
pop eax
shr eax, 1
jz .h_rounddowndiv ; jump by result of and eax, 1
inc eax
.h_rounddowndiv:
cmp eax, 0x20000
jle .h_best_divok
mov eax, 0x1FFFF
.h_best_divok:
mov ecx, eax
mov eax, H_CLK * 16 / 10
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jz .rounddownbaud
inc ecx
jmp .rounddownbaud
.c_nextbaud3:
mov eax, C_CLK ; eax - best_divisor
xor edx, edx
div esi
push eax
and eax, 1
pop eax
shr eax, 1
jnz .c_rounddowndiv ; jump by result of and eax, 1
inc eax
.c_rounddowndiv:
cmp eax, 0x20000
jle .c_best_divok
mov eax, 0x1FFFF
.c_best_divok:
mov ecx, eax
mov eax, C_CLK
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jnz .rounddownbaud
inc ecx
.rounddownbaud:
mov edx, eax ; edx - encoded_divisor
shr edx, 3
and eax, 0x7
push 7 6 5 1 4 2 3 0
mov eax, [esp + eax * 4]
shl eax, 14
or edx, eax
add esp, 32
.calcend:
mov eax, edx ; eax - *value
mov ecx, edx ; ecx - *index
and eax, 0xFFFF
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jge .foxyindex
shr ecx, 16
ret
.foxyindex:
shr ecx, 8
and ecx, 0xFF00
or ecx, [ebx + ftdi_context.index]
ret
endp
proc control_callback stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
.buffer:DWORD, .length:DWORD, .calldata:DWORD
DEBUGF 1, 'K : status is %d\n', [.status]
DEBUGF L_DBG, 'ftdi: status is %d\n', [.status]
mov ecx, [.calldata]
mov eax, [ecx]
mov ebx, [ecx+4]
@@ -1011,7 +1028,7 @@ endp
proc bulk_callback stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
.buffer:DWORD, .length:DWORD, .calldata:DWORD
DEBUGF 1, 'K : status is %d\n', [.status]
DEBUGF L_DBG, 'ftdi: status is %d\n', [.status]
mov ecx, [.calldata]
mov eax, [ecx]
mov ebx, [ecx+4]
@@ -1034,7 +1051,7 @@ endp
proc DeviceDisconnected stdcall uses ebx esi edi, .device_data:DWORD
DEBUGF 1, 'K : FTDI deleting device data 0x%x\n', [.device_data]
DEBUGF L_DBG, 'ftdi: deleting device data 0x%x\n', [.device_data]
mov esi, [.device_data]
mov eax, [esi + ftdi_context.readBufPtr]
test eax, eax
@@ -1062,7 +1079,7 @@ proc bulk_in_complete stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
mov eax, [.status]
test eax, eax
jz @f
DEBUGF 2, 'ftdi: bulk in error %x\n', eax
DEBUGF L_ERR, 'ftdi: bulk in error %x\n', eax
@@:
mov ebx, [.calldata]
btr dword [ebx + ftdi_context.writeBufLock], 0
@@ -1075,7 +1092,7 @@ proc bulk_out_complete stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
mov eax, [.status]
test eax, eax
jz @f
DEBUGF 2, 'ftdi: bulk out error %x\n', eax
DEBUGF L_ERR, 'ftdi: bulk out error %x\n', eax
@@:
mov ebx, [.calldata]
mov ecx, [.length]
@@ -1092,18 +1109,18 @@ proc bulk_out_complete stdcall uses ebx edi esi, .pipe:DWORD, .status:DWORD, \
endp
proc uart_startup stdcall uses ebx, data:dword, conf:dword
DEBUGF 1, "ftdi: startup %x %x\n", [data], [conf]
DEBUGF L_DBG, "ftdi: startup %x %x\n", [data], [conf]
stdcall uart_reconf, [data], [conf]
test eax, eax
jz @f
DEBUGF 2, "ftdi: uart reconf error %x\n", eax
DEBUGF L_ERR, "ftdi: uart reconf error %x\n", eax
jmp .exit
@@:
mov ebx, [data]
invoke TimerHS, 2, 2, uart_rx, ebx
test eax, eax
jnz @f
DEBUGF 2, "ftdi: timer creation error\n"
DEBUGF L_ERR, "ftdi: timer creation error\n"
or eax, -1
jmp .exit
@@:
@@ -1114,7 +1131,7 @@ proc uart_startup stdcall uses ebx, data:dword, conf:dword
endp
proc uart_shutdown stdcall uses ebx, data:dword
DEBUGF 1, "ftdi: shutdown %x\n", [data]
DEBUGF L_DBG, "ftdi: shutdown %x\n", [data]
mov ebx, [data]
cmp [ebx + ftdi_context.rx_timer], 0
jz @f
@@ -1246,137 +1263,14 @@ proc uart_rx stdcall uses ebx esi, data:dword
ret
endp
proc ftdi_set_baudrate stdcall uses ebx, dev:dword, baud:dword
proc ftdi_set_baudrate stdcall uses ebx esi, dev:dword, baud:dword
locals
ConfPacket rb 8
endl
mov ebx, [dev]
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jl .c_clk
imul eax, [baud], 10
cmp eax, H_CLK / 0x3FFF
jle .c_clk
.h_clk:
cmp dword [baud], H_CLK / 10
jl .h_nextbaud1
xor edx, edx
mov ecx, H_CLK / 10
jmp .calcend
mov esi, [baud]
call ftdi_calc_baud_divisor
.c_clk:
cmp dword [baud], C_CLK / 16
jl .c_nextbaud1
xor edx, edx
mov ecx, C_CLK / 16
jmp .calcend
.h_nextbaud1:
cmp dword [baud], H_CLK / (10 + 10 / 2)
jl .h_nextbaud2
mov edx, 1
mov ecx, H_CLK / (10 + 10 / 2)
jmp .calcend
.c_nextbaud1:
cmp dword [baud], C_CLK / (16 + 16 / 2)
jl .c_nextbaud2
mov edx, 1
mov ecx, C_CLK/(16 + 16 / 2)
jmp .calcend
.h_nextbaud2:
cmp dword [baud], H_CLK / (2 * 10)
jl .h_nextbaud3
mov edx, 2
mov ecx, H_CLK / (2 * 10)
jmp .calcend
.c_nextbaud2:
cmp dword [baud], C_CLK / (2 * 16)
jl .c_nextbaud3
mov edx, 2
mov ecx, C_CLK / (2 * 16)
jmp .calcend
.h_nextbaud3:
mov eax, H_CLK * 16 / 10 ; eax - best_divisor
xor edx, edx
div dword [baud]
push eax
and eax, 1
pop eax
shr eax, 1
jz .h_rounddowndiv ; jump by result of and eax, 1
inc eax
.h_rounddowndiv:
cmp eax, 0x20000
jle .h_best_divok
mov eax, 0x1FFFF
.h_best_divok:
mov ecx, eax
mov eax, H_CLK * 16 / 10
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jz .rounddownbaud
inc ecx
jmp .rounddownbaud
.c_nextbaud3:
mov eax, C_CLK ; eax - best_divisor
xor edx, edx
div dword [baud]
push eax
and eax, 1
pop eax
shr eax, 1
jnz .c_rounddowndiv ; jump by result of and eax, 1
inc eax
.c_rounddowndiv:
cmp eax, 0x20000
jle .c_best_divok
mov eax, 0x1FFFF
.c_best_divok:
mov ecx, eax
mov eax, C_CLK
xor edx, edx
div ecx
xchg ecx, eax ; ecx - best_baud
push ecx
and ecx, 1
pop ecx
shr ecx, 1
jnz .rounddownbaud
inc ecx
.rounddownbaud:
mov edx, eax ; edx - encoded_divisor
shr edx, 3
and eax, 0x7
push 7 6 5 1 4 2 3 0
mov eax, [esp + eax * 4]
shl eax, 14
or edx, eax
add esp, 32
.calcend:
mov eax, edx ; eax - *value
mov ecx, edx ; ecx - *index
and eax, 0xFFFF
cmp [ebx + ftdi_context.chipType], TYPE_2232H
jge .foxyindex
shr ecx, 16
jmp .preparepacket
.foxyindex:
shr ecx, 8
and ecx, 0xFF00
or ecx, [ebx + ftdi_context.index]
.preparepacket:
mov word [ConfPacket], (FTDI_DEVICE_OUT_REQTYPE) \
+ (SIO_SET_BAUDRATE_REQUEST shl 8)
mov word [ConfPacket + 2], ax
@@ -1451,10 +1345,9 @@ uart_drv:
dd uart_tx
uart_drv_end:
serial_drv_entry dd 0
include_debug_strings
data fixups
end data
;for DEBUGF macro
include_debug_strings
serial_drv_entry dd ?
+10 -1
View File
@@ -2204,6 +2204,9 @@ proc acm_arm_rx
endp
proc acm_add_device stdcall uses ebx esi edi, .pipe0:dword, .config:dword, .interface:dword
locals
.pinfo rb sizeof.SP_PORT_INFO
endl
; 1. Parse the descriptors (the ACM data interface is alt setting 0).
xor eax, eax
@@ -2264,7 +2267,12 @@ proc acm_add_device stdcall uses ebx esi edi, .pipe0:dword, .config:dword, .inte
cmp [serial_drv_entry], 0
je .no_serial
stdcall serial_add_port, acm_sp_driver, ebx
mov dword [.pinfo+SP_PORT_INFO.size], sizeof.SP_PORT_INFO
mov dword [.pinfo+SP_PORT_INFO.driver], acm_port_name
; TODO obtain iManufacturer, iProduct and iSerial strings
mov dword [.pinfo+SP_PORT_INFO.descr], 0
lea ecx, [.pinfo]
stdcall serial_add_port, acm_sp_driver, ebx, ecx
mov [ebx+acm_dev.PortHandle], eax
test eax, eax
jz .no_serial
@@ -2652,6 +2660,7 @@ endp
; strings and static data
my_service db 'usbcdc', 0
acm_port_name db 'cdc-acm', 0
netdev_name db 'USB CDC-NCM', 0
ecm_netdev_name db 'USB CDC-ECM', 0
ecm_zlp_dummy db 0 ; address for zero-length transfers
+8 -2
View File
@@ -1754,8 +1754,14 @@ proc disk_read_write stdcall uses ebx esi edi, \
mov eax, [numsectors]
mov eax, [eax]
; 2. The transfer length for SCSI_{READ,WRITE}10 commands can not be greater
; than 0xFFFF, so split the request to slices with <= 0xFFFF sectors.
max_sectors_at_time = 0xFFFF
; than 0xFFFF sectors, but that is not the practical limit: the field size is
; the only thing the standard bounds, while real sticks hang their firmware on
; multi-megabyte single commands. The kernel disk cache asks for as much as
; CACHE_MAX_ALLOC_SIZE (4 MB) in one call, i.e. 8192 sectors, and that is
; exactly where such sticks stop answering and re-enumerate. Linux caps
; usb-storage at 240 sectors (120 KB) for the same reason; do the same and
; split larger requests into slices.
max_sectors_at_time = 240
.split:
push eax ; .length_rest
cmp eax, max_sectors_at_time
+3
View File
@@ -0,0 +1,3 @@
if tup.getconfig("NO_FASM") ~= "" then return end
ROOT = "../../.."
tup.rule("xhci.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "%B.sys")
File diff suppressed because it is too large. Load diff
+993
View File
@@ -0,0 +1,993 @@
; Device slots, contexts and pipes for the xHCI driver.
; This file is included from xhci.asm.
; =============================================================================
; ============================ Context helpers ================================
; =============================================================================
; Returns the address of one context inside a context structure.
; in: eax = base of the structure, ecx = index of the context,
; esi -> usb_controller.
; out: eax = address of the context.
proc xhci_context
push ecx edx
mov edx, [esi+xhci_controller.ContextSize-XCD]
imul edx, ecx
add eax, edx
pop edx ecx
ret
endp
; Zeroes the Input Context. The caller must hold CmdLock.
; in: esi -> usb_controller.
proc xhci_clear_input_ctx
push eax ecx edi
mov edi, [esi+xhci_controller.InputCtx-XCD]
xor eax, eax
mov ecx, 33*64/4
rep stosd
pop edi ecx eax
ret
endp
; Returns the pipe of the default control endpoint of the same device, which
; represents the device as a whole.
; in: ebx -> xhci_pipe. out: eax -> xhci_pipe or 0.
proc xhci_ctrl_pipe
mov eax, [ebx+xhci_pipe.DevPage]
test eax, eax
jz .nothing
mov eax, [eax+XHCI_PIPES_OFS+1*4]
test eax, eax
jz .nothing
sub eax, sizeof.xhci_pipe
.nothing:
ret
endp
; Fills the Slot Context of the Input Context from the device description kept
; in a pipe. The caller must hold CmdLock.
; in: esi -> usb_controller, ebx -> xhci_pipe describing the device,
; ecx = value for the Context Entries field.
proc xhci_fill_slot_ctx
push eax ecx edx edi
mov eax, [esi+xhci_controller.InputCtx-XCD]
push ecx
movi ecx, 1
call xhci_context
pop ecx
mov edi, eax
; dword 0: Route String, Speed and Context Entries.
mov eax, [ebx+xhci_pipe.Route]
and eax, 0FFFFFh
if XHCI_SUPERSPEED
; A SuperSpeed root-port device carries the raw PORTSC speed identifier;
; its kernel-visible Speed pretends high-speed and must not get here.
mov edx, [ebx+xhci_pipe.PSIV]
test edx, edx
jnz .havespeed
end if
mov edx, [ebx+xhci_pipe.Speed]
cmp edx, USB_SPEED_FS
jz .fs
cmp edx, USB_SPEED_LS
jz .ls
movi edx, XHCI_PSI_HS
jmp .havespeed
.fs:
movi edx, XHCI_PSI_FS
jmp .havespeed
.ls:
movi edx, XHCI_PSI_LS
.havespeed:
shl edx, 20
or eax, edx
shl ecx, 27
or eax, ecx
mov [edi], eax
; dword 1: Root Hub Port Number.
mov eax, [ebx+xhci_pipe.RootPort]
shl eax, 16
mov [edi+4], eax
; dword 2: the Transaction Translator, if the device is served by one.
mov eax, [ebx+xhci_pipe.TTSlot]
test eax, eax
jz @f
mov edx, [ebx+xhci_pipe.TTPort]
shl edx, 8
or eax, edx
@@:
mov [edi+8], eax
and dword [edi+12], 0
pop edi edx ecx eax
ret
endp
; Fills the Endpoint Context of the Input Context for the given pipe.
; The caller must hold CmdLock.
; in: esi -> usb_controller, ebx -> xhci_pipe.
proc xhci_fill_ep_ctx
push eax ecx edx edi
mov eax, [esi+xhci_controller.InputCtx-XCD]
mov ecx, [ebx+xhci_pipe.DCI]
inc ecx
call xhci_context
mov edi, eax
; dword 0: Interval.
mov eax, [ebx+xhci_pipe.Interval]
shl eax, 16
mov [edi], eax
; dword 1: Error Count, Endpoint Type, Max Burst Size and Max Packet Size.
mov eax, [ebx+xhci_pipe.EpType]
shl eax, 3
or eax, 3 shl 1 ; three retries before giving up
mov edx, [ebx+xhci_pipe.MaxPacket]
mov ecx, edx
shr ecx, 11
and ecx, 3 ; extra transactions per microframe
shl ecx, 8
or eax, ecx
if XHCI_SUPERSPEED
; A SuperSpeed bulk endpoint may allow bursts of several packets; the field
; shares its bits with the extra-transactions ones, which are zero then.
mov ecx, [ebx+xhci_pipe.MaxBurst]
shl ecx, 8
or eax, ecx
end if
and edx, 7FFh
shl edx, 16
or eax, edx
mov [edi+4], eax
; dwords 2 and 3: the TR Dequeue Pointer with the Dequeue Cycle State.
mov eax, [ebx+xhci_pipe.Enqueue]
shl eax, 4
add eax, [ebx+xhci_pipe.RingPhys]
or eax, [ebx+xhci_pipe.Cycle]
mov [edi+8], eax
and dword [edi+12], 0
; dword 4: Average TRB Length, only a hint for the bandwidth scheduler.
mov eax, [ebx+xhci_pipe.MaxPacket]
and eax, 7FFh
cmp [ebx+xhci_pipe.EpType], XHCI_EP_CONTROL
jnz @f
movi eax, 8
@@:
mov [edi+16], eax
and dword [edi+20], 0
pop edi edx ecx eax
ret
endp
; =============================================================================
; ============================== Slot commands ================================
; =============================================================================
; Issues the Address Device command for a newly created default control pipe.
; in: esi -> usb_controller, ebx -> xhci_pipe. out: eax = 0 on failure.
proc xhci_address_device
push ebx ecx edx edi
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
mov edx, [esi+xhci_controller.InputCtx-XCD]
mov dword [edx+4], 3 ; add the Slot Context and endpoint zero
movi ecx, 1
call xhci_fill_slot_ctx
call xhci_fill_ep_ctx
mov [ebx+xhci_pipe.MaxDCI], 1
; Point the DCBAA entry of the slot at the Device Context.
mov eax, [esi+xhci_controller.CommonPage-XCD]
mov ecx, [ebx+xhci_pipe.SlotId]
mov edx, [ebx+xhci_pipe.DevPagePhys]
mov [eax+ecx*8], edx
and dword [eax+ecx*8+4], 0
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_ADDRESS_DEV shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
push ebx
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
pop ebx
push eax
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
pop eax
cmp eax, XHCI_CC_SUCCESS
jz .ok
DEBUGF 1,'K : XHCI: Address Device failed, code %d\n',eax
xor eax, eax
jmp .nothing
.ok:
movi eax, 1
.nothing:
pop edi edx ecx ebx
ret
endp
; Issues a Configure Endpoint command that adds the given endpoint.
; in: esi -> usb_controller, ebx -> xhci_pipe of the endpoint,
; edi -> xhci_pipe of the default control endpoint of the same device.
; out: eax = completion code.
proc xhci_configure_endpoint
push ebx ecx edx esi edi
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
; Drop the endpoint and add it again, so that reopening an endpoint that has
; been closed before also works.
mov ecx, [ebx+xhci_pipe.DCI]
movi eax, 1
shl eax, cl
mov edx, [esi+xhci_controller.InputCtx-XCD]
mov [edx], eax
or eax, 1 ; the Slot Context is always added
mov [edx+4], eax
call xhci_fill_ep_ctx
; The Context Entries field must cover every endpoint in use by the device.
mov ecx, [ebx+xhci_pipe.DCI]
cmp ecx, [edi+xhci_pipe.MaxDCI]
jae @f
mov ecx, [edi+xhci_pipe.MaxDCI]
@@:
mov [edi+xhci_pipe.MaxDCI], ecx
push ebx
mov ebx, edi
call xhci_fill_slot_ctx
pop ebx
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_CONFIG_EP shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
push ebx
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
pop ebx
push eax
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
pop eax
pop edi esi edx ecx ebx
ret
endp
; Tells the controller where the endpoint has to continue from.
; in: esi -> usb_controller, ebx -> xhci_pipe.
proc xhci_set_dequeue
pushad
cmp [ebx+xhci_pipe.SlotId], 0
jz .nothing
mov eax, [ebx+xhci_pipe.Dequeue]
shl eax, 4
add eax, [ebx+xhci_pipe.RingPhys]
or eax, [ebx+xhci_pipe.Cycle]
mov ecx, [ebx+xhci_pipe.DCI]
shl ecx, 16
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, ecx
or edx, XHCI_TRB_SET_DEQ shl 10
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_sync
cmp eax, XHCI_CC_SUCCESS
jz .nothing
DEBUGF 1,'K : XHCI: Set TR Dequeue Pointer failed, code %d\n',eax
.nothing:
popad
ret
endp
; =============================================================================
; =============================== New device ==================================
; =============================================================================
; Called from xhci_port_init and from the hub support code when a new device
; has been connected and reset. Enables a device slot for it and hands it over
; to the protocol layer.
; in: esi -> usb_controller, eax = speed. out: eax = 0 on failure.
proc xhci_new_device
push ebx ecx edx edi
mov [esi+usb_controller.ResettingSpeed], al
; 1. Reserve room for the pseudo-pipe that describes the new device. Only the
; fields read by xhci_init_pipe are filled in; the layout matches a real pipe,
; so the result can be passed to usb_new_device as a usb_pipe pointer.
sub esp, sizeof.xhci_pipe + 4
mov ebx, esp
push ebx
mov edi, ebx
xor eax, eax
mov ecx, (sizeof.xhci_pipe + 4)/4
rep stosd
pop ebx
mov [ebx+sizeof.xhci_pipe], esi ; usb_pipe.Controller
movzx eax, [esi+usb_controller.ResettingSpeed]
mov [ebx+xhci_pipe.Speed], eax
; 2. Compute the root hub port, the route string and the tier of the device.
movzx edx, [esi+usb_controller.ResettingPort]
mov edi, [esi+usb_controller.ResettingHub]
test edi, edi
jnz .behind_hub
mov eax, [esi+xhci_controller.PortMap-XCD+edx*4]
mov [ebx+xhci_pipe.RootPort], eax
if XHCI_SUPERSPEED
mov eax, [esi+xhci_controller.ResettingPSIV-XCD]
mov [ebx+xhci_pipe.PSIV], eax
end if
jmp .have_topology
.behind_hub:
; The parent hub is a device too, and its own pipe carries the topology data.
mov eax, [edi+USB_HUB_CONFIGPIPE]
sub eax, sizeof.xhci_pipe
mov ecx, [eax+xhci_pipe.RootPort]
mov [ebx+xhci_pipe.RootPort], ecx
mov ecx, [eax+xhci_pipe.Depth]
mov eax, [eax+xhci_pipe.Route]
; The route string holds one nibble per tier, at most five of them.
cmp ecx, 5
jae .have_route
push ecx edx
shl ecx, 2
inc edx ; the route uses 1-based port numbers
cmp edx, 15
jbe @f
movi edx, 15
@@:
shl edx, cl
or eax, edx
pop edx ecx
.have_route:
inc ecx
mov [ebx+xhci_pipe.Depth], ecx
mov [ebx+xhci_pipe.Route], eax
; 3. Low- and full-speed devices behind a high-speed hub need the address of
; the Transaction Translator that serves them.
cmp [ebx+xhci_pipe.Speed], USB_SPEED_HS
jz .have_topology
push ebx
mov ecx, edx
mov edx, edi
invoke usbhc_api.usb_get_tt
pop ebx
test edx, edx
jz .have_topology
sub edx, sizeof.xhci_pipe
mov eax, [edx+xhci_pipe.SlotId]
mov [ebx+xhci_pipe.TTSlot], eax
inc ecx
mov [ebx+xhci_pipe.TTPort], ecx
.have_topology:
; 4. Ask the controller for a device slot.
xor eax, eax
push ebx
xor ebx, ebx
xor ecx, ecx
mov edx, XHCI_TRB_ENABLE_SLOT shl 10
call xhci_cmd_sync
pop ebx
cmp eax, XHCI_CC_SUCCESS
jnz .fail
test edx, edx
jz .fail
mov [ebx+xhci_pipe.SlotId], edx
DEBUGF 1,'K : XHCI new device: slot %d, root port %d, route %x, speed %d\n',edx,[ebx+xhci_pipe.RootPort],[ebx+xhci_pipe.Route],[ebx+xhci_pipe.Speed]
; 5. Hand the device over to the protocol layer. It opens the pipe of the
; default control endpoint, and that is where the slot is really addressed.
lea ecx, [ebx+sizeof.xhci_pipe]
invoke usbhc_api.usb_new_device
test eax, eax
jnz .done
; 6. The protocol layer has failed; release the slot again.
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_DISABLE_SLOT shl 10
xor eax, eax
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_sync
xor eax, eax
jmp .done
.fail:
dbgstr 'XHCI: Enable Slot failed'
xor eax, eax
.done:
add esp, sizeof.xhci_pipe + 4
pop edi edx ecx ebx
ret
endp
; =============================================================================
; ================================= Pipes =====================================
; =============================================================================
proc xhci_alloc_pipe
push ebx ecx edi
mov ebx, xhci_ep_mutex
invoke usbhc_api.usb_allocate_common, sizeof.xhci_pipe + sizeof.usb_pipe
test eax, eax
jz @f
; Zero the whole block: the kernel may call FreePipe for a pipe whose InitPipe
; has never run, and that path must not act on garbage.
mov edi, eax
push eax
xor eax, eax
movi ecx, (sizeof.xhci_pipe + sizeof.usb_pipe + 3)/4
rep stosd
pop eax
add eax, sizeof.xhci_pipe
@@:
pop edi ecx ebx
ret
endp
proc xhci_free_pipe stdcall, ptr:dword
push ebx esi edi
mov ebx, [ptr]
sub ebx, sizeof.xhci_pipe
mov esi, [ebx+sizeof.xhci_pipe+usb_pipe.Controller]
test esi, esi
jz .free
cmp [ebx+xhci_pipe.SlotId], 0
jz .drop_pipe
cmp [ebx+xhci_pipe.DCI], 1
jnz .drop_pipe
; This is the default control endpoint, that is, the handle of the whole
; device: release the slot together with the per-device page.
mov ecx, [ebx+xhci_pipe.SlotId]
mov edx, ecx
shl edx, 24
or edx, XHCI_TRB_DISABLE_SLOT shl 10
xor eax, eax
push ebx
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_sync
pop ebx
; The controller may access the Device Context until the command above
; completes, so only now may the DCBAA entry and the slot table forget it.
mov ecx, [ebx+xhci_pipe.SlotId]
mov edi, [esi+xhci_controller.CommonPage-XCD]
and dword [edi+ecx*8], 0
and dword [edi+ecx*8+4], 0
and [esi+xhci_controller.SlotPages-XCD+ecx*4], 0
mov eax, [ebx+xhci_pipe.DevPage]
test eax, eax
jz .drop_ring
invoke KernelFree, eax
and [ebx+xhci_pipe.DevPage], 0
jmp .drop_ring
.drop_pipe:
; Remove the pipe from the per-device table, if it is still listed there.
; On disconnect the kernel releases the pipes of a device in arbitrary order,
; and the pipe of the default control endpoint - the owner of the per-device
; page - may well be freed before this one, taking the page with it. The
; authoritative pointer is the one in SlotPages: it is cleared when the slot
; is released, so it can never point to freed memory.
mov ecx, [ebx+xhci_pipe.SlotId]
test ecx, ecx
jz .drop_ring
mov eax, [esi+xhci_controller.SlotPages-XCD+ecx*4]
test eax, eax
jz .drop_ring
mov ecx, [ebx+xhci_pipe.DCI]
cmp ecx, 32
jae .drop_ring
and dword [eax+XHCI_PIPES_OFS+ecx*4], 0
.drop_ring:
mov eax, [ebx+xhci_pipe.Ring]
test eax, eax
jz @f
invoke KernelFree, eax
and [ebx+xhci_pipe.Ring], 0
@@:
mov eax, [ebx+xhci_pipe.RingMap]
test eax, eax
jz .free
invoke KernelFree, eax
and [ebx+xhci_pipe.RingMap], 0
.free:
pop edi esi ebx
mov eax, [ptr]
sub eax, sizeof.xhci_pipe
invoke usbhc_api.usb_free_common, eax
ret
endp
; Allocates the transfer ring of a pipe.
; in: ebx -> xhci_pipe. out: eax = 0 on failure.
proc xhci_alloc_ring
push ecx edx
call xhci_alloc_page
test eax, eax
jz .nothing
mov [ebx+xhci_pipe.RingMap], eax
call xhci_alloc_page
test eax, eax
jnz @f
invoke KernelFree, [ebx+xhci_pipe.RingMap]
and [ebx+xhci_pipe.RingMap], 0
xor eax, eax
jmp .nothing
@@:
mov [ebx+xhci_pipe.Ring], eax
mov [ebx+xhci_pipe.RingPhys], edx
; The last entry returns to the beginning of the ring and toggles the cycle.
lea ecx, [eax+(XHCI_RING_TRBS-1)*16]
mov [ecx], edx
mov dword [ecx+12], (XHCI_TRB_LINK shl 10) + XHCI_TRB_TC
and [ebx+xhci_pipe.Enqueue], 0
and [ebx+xhci_pipe.Dequeue], 0
and [ebx+xhci_pipe.Reserved], 0
and [ebx+xhci_pipe.FirstFix], 0
mov [ebx+xhci_pipe.Cycle], XHCI_TRB_C
movi eax, 1
.nothing:
pop edx ecx
ret
endp
; Stores the pipe in the per-device table used by the event ring handler.
; in: ebx -> xhci_pipe.
proc xhci_register_pipe
push eax ecx edx
mov eax, [ebx+xhci_pipe.DevPage]
test eax, eax
jz @f
mov ecx, [ebx+xhci_pipe.DCI]
cmp ecx, 32
jae @f
lea edx, [ebx+sizeof.xhci_pipe]
mov [eax+XHCI_PIPES_OFS+ecx*4], edx
@@:
pop edx ecx eax
ret
endp
; Computes the Interval field of the Endpoint Context of an interrupt endpoint.
; The kernel passes bInterval from the endpoint descriptor: for high-speed
; devices it is an exponent of 125 us periods, for low- and full-speed devices
; it is a number of frames.
; in: ebx -> xhci_pipe, eax = bInterval.
proc xhci_calc_interval
push eax ecx
cmp [ebx+xhci_pipe.Speed], USB_SPEED_HS
jnz .low_speed
test eax, eax
jz @f
dec eax
@@:
jmp .clamp
.low_speed:
; One frame equals eight periods of 125 us, hence the offset of three.
test eax, eax
jnz @f
movi eax, 1
@@:
bsr ecx, eax
lea eax, [ecx+3]
.clamp:
cmp eax, 15
jbe @f
movi eax, 15
@@:
mov [ebx+xhci_pipe.Interval], eax
pop ecx eax
ret
endp
; Called from usb_open_pipe.
; in: edi -> usb_pipe for the target, ecx -> usb_pipe of the config pipe,
; esi -> usb_controller, eax -> usb_gtd of the first descriptor,
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type,
; [ebp+24] = interval.
; out: eax = 0 on failure.
proc xhci_init_pipe
virtual at ebp+8
.config_pipe dd ?
.endpoint dd ?
.maxpacket dd ?
.type dd ?
.interval dd ?
end virtual
push ebx
sub edi, sizeof.xhci_pipe
sub ecx, sizeof.xhci_pipe
mov ebx, edi ; ebx -> xhci_pipe being initialized
; 1. Copy the description of the device from the config pipe.
mov eax, [ecx+xhci_pipe.SlotId]
mov [ebx+xhci_pipe.SlotId], eax
mov eax, [ecx+xhci_pipe.DevPage]
mov [ebx+xhci_pipe.DevPage], eax
mov eax, [ecx+xhci_pipe.DevPagePhys]
mov [ebx+xhci_pipe.DevPagePhys], eax
mov eax, [ecx+xhci_pipe.Speed]
mov [ebx+xhci_pipe.Speed], eax
mov eax, [ecx+xhci_pipe.RootPort]
mov [ebx+xhci_pipe.RootPort], eax
mov eax, [ecx+xhci_pipe.Route]
mov [ebx+xhci_pipe.Route], eax
mov eax, [ecx+xhci_pipe.Depth]
mov [ebx+xhci_pipe.Depth], eax
mov eax, [ecx+xhci_pipe.TTSlot]
mov [ebx+xhci_pipe.TTSlot], eax
mov eax, [ecx+xhci_pipe.TTPort]
mov [ebx+xhci_pipe.TTPort], eax
if XHCI_SUPERSPEED
mov eax, [ecx+xhci_pipe.PSIV]
mov [ebx+xhci_pipe.PSIV], eax
end if
; 2. Work out the Device Context Index and the endpoint type.
mov eax, [.endpoint]
test eax, eax
jz .control_ep
mov ecx, eax
and ecx, 15
add ecx, ecx
test al, 80h
jz @f
inc ecx
or [ebx+xhci_pipe.Flags], XHCI_PIPE_IN
@@:
mov [ebx+xhci_pipe.DCI], ecx
mov eax, [.type]
cmp eax, BULK_PIPE
jz .bulk
cmp eax, INTERRUPT_PIPE
jz .interrupt
; A control endpoint other than endpoint zero is unusual but legal.
mov [ebx+xhci_pipe.EpType], XHCI_EP_CONTROL
jmp .have_type
.bulk:
movi eax, XHCI_EP_BULK_OUT
test [ebx+xhci_pipe.Flags], XHCI_PIPE_IN
jz @f
movi eax, XHCI_EP_BULK_IN
@@:
mov [ebx+xhci_pipe.EpType], eax
jmp .have_type
.interrupt:
movi eax, XHCI_EP_INT_OUT
test [ebx+xhci_pipe.Flags], XHCI_PIPE_IN
jz @f
movi eax, XHCI_EP_INT_IN
@@:
mov [ebx+xhci_pipe.EpType], eax
mov eax, [.interval]
call xhci_calc_interval
.have_type:
mov eax, [.maxpacket]
mov [ebx+xhci_pipe.MaxPacket], eax
if XHCI_SUPERSPEED
call xhci_ss_get_burst
end if
jmp .alloc_ring
.control_ep:
; The default control endpoint always has index one. Until the real packet size
; is known from the device descriptor, use the value the specification requires
; for the speed of the device: the kernel asks for 64 regardless of the speed,
; which is wrong for low- and full-speed devices.
mov [ebx+xhci_pipe.DCI], 1
mov [ebx+xhci_pipe.EpType], XHCI_EP_CONTROL
movi eax, 64
cmp [ebx+xhci_pipe.Speed], USB_SPEED_HS
jz @f
movi eax, 8
@@:
if XHCI_SUPERSPEED
; A SuperSpeed device always uses 512 bytes on the default control endpoint.
cmp [ebx+xhci_pipe.PSIV], XHCI_PSI_SS
jb @f
mov eax, 512
@@:
end if
mov [ebx+xhci_pipe.MaxPacket], eax
.alloc_ring:
; 3. Allocate the transfer ring.
call xhci_alloc_ring
test eax, eax
jz .fail
; 4. Choose the software list the pipe belongs to and insert it there. The
; hardware knows nothing about these lists; they exist only so that the kernel
; can walk all pipes and reinsert an aborted one.
lea edx, [esi+xhci_controller.ControlED-XCD]
cmp [.type], BULK_PIPE
jb @f
lea edx, [esi+xhci_controller.BulkED-XCD]
jz @f
lea edx, [esi+xhci_controller.IntED-XCD]
@@:
lea edi, [ebx+sizeof.xhci_pipe]
mov [edi+usb_pipe.BaseList], edx
mov ecx, [edx+usb_pipe.NextVirt]
mov [edi+usb_pipe.NextVirt], ecx
mov [edi+usb_pipe.PrevVirt], edx
mov [ecx+usb_pipe.PrevVirt], edi
mov [edx+usb_pipe.NextVirt], edi
; 5. Now do the hardware part.
cmp [.endpoint], 0
jz .address_device
call xhci_register_pipe
mov edi, [.config_pipe]
sub edi, sizeof.xhci_pipe
call xhci_configure_endpoint
xhci_trace 'K : XHCI open pipe: slot %d dci %d\n', [ebx+xhci_pipe.SlotId], [ebx+xhci_pipe.DCI]
cmp eax, XHCI_CC_SUCCESS
jz .success
DEBUGF 1,'K : XHCI: Configure Endpoint failed, code %d\n',eax
jmp .unlink_fail
.address_device:
; 6. This is a new device: allocate its Device Context, publish the slot and
; let the controller give the device a bus address.
call xhci_alloc_page
test eax, eax
jz .unlink_fail
mov [ebx+xhci_pipe.DevPage], eax
mov [ebx+xhci_pipe.DevPagePhys], edx
mov ecx, [ebx+xhci_pipe.SlotId]
mov [esi+xhci_controller.SlotPages-XCD+ecx*4], eax
call xhci_register_pipe
call xhci_address_device
test eax, eax
jz .free_devpage
.success:
; usb_open_pipe keeps the pointer to the new pipe in edi across this call, so
; it has to be handed back untouched; the branch above has overwritten it with
; the pipe of the default control endpoint.
lea edi, [ebx+sizeof.xhci_pipe]
pop ebx
movi eax, 1
ret
.free_devpage:
mov ecx, [ebx+xhci_pipe.SlotId]
and [esi+xhci_controller.SlotPages-XCD+ecx*4], 0
mov eax, [ebx+xhci_pipe.DevPage]
invoke KernelFree, eax
and [ebx+xhci_pipe.DevPage], 0
.unlink_fail:
; Undo the insertion into the software list before failing.
lea edi, [ebx+sizeof.xhci_pipe]
mov eax, [edi+usb_pipe.NextVirt]
mov edx, [edi+usb_pipe.PrevVirt]
mov [eax+usb_pipe.PrevVirt], edx
mov [edx+usb_pipe.NextVirt], eax
.fail:
lea edi, [ebx+sizeof.xhci_pipe]
pop ebx
xor eax, eax
ret
endp
; Removes the pipe from the hardware configuration of the device.
; in: esi -> usb_controller, ebx -> usb_pipe.
proc xhci_unlink_pipe
pushad
sub ebx, sizeof.xhci_pipe
cmp [ebx+xhci_pipe.SlotId], 0
jz .nothing
cmp [ebx+xhci_pipe.DCI], 1
jz .nothing ; the slot itself is released by FreePipe
call xhci_ctrl_pipe
test eax, eax
jz .nothing
mov edi, eax ; edi -> pipe of endpoint zero
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
mov ecx, [ebx+xhci_pipe.DCI]
movi eax, 1
shl eax, cl
mov edx, [esi+xhci_controller.InputCtx-XCD]
mov [edx], eax ; drop this endpoint
mov dword [edx+4], 1 ; keep the Slot Context
mov ecx, [edi+xhci_pipe.MaxDCI]
test ecx, ecx
jnz @f
movi ecx, 1
@@:
push ebx
mov ebx, edi
call xhci_fill_slot_ctx
pop ebx
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_CONFIG_EP shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
.nothing:
popad
ret
endp
; Temporarily removes the pipe from the hardware schedule.
; in: esi -> usb_controller, ebx -> usb_pipe.
proc xhci_disable_pipe
pushad
sub ebx, sizeof.xhci_pipe
cmp [ebx+xhci_pipe.SlotId], 0
jz .nothing
mov ecx, [ebx+xhci_pipe.DCI]
shl ecx, 16
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, ecx
or edx, XHCI_TRB_STOP_EP shl 10
xor eax, eax
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_sync
.nothing:
popad
ret
endp
; Reinserts the pipe into the hardware schedule after xhci_disable_pipe, with
; an empty transfer queue.
; in: esi -> usb_controller, ebx -> usb_pipe,
; edx -> current descriptor, eax -> new last descriptor.
proc xhci_enable_pipe
pushad
sub ebx, sizeof.xhci_pipe
mov eax, [ebx+xhci_pipe.Ring]
test eax, eax
jz .nothing
; The queue is empty now, so the ring can be restarted from its beginning.
mov edi, eax
xor eax, eax
mov ecx, 0x1000/4
rep stosd
mov edi, [ebx+xhci_pipe.RingMap]
mov ecx, 0x1000/4
rep stosd
mov edi, [ebx+xhci_pipe.Ring]
add edi, (XHCI_RING_TRBS-1)*16
mov eax, [ebx+xhci_pipe.RingPhys]
mov [edi], eax
mov dword [edi+12], (XHCI_TRB_LINK shl 10) + XHCI_TRB_TC
and [ebx+xhci_pipe.Enqueue], 0
and [ebx+xhci_pipe.Dequeue], 0
and [ebx+xhci_pipe.Reserved], 0
and [ebx+xhci_pipe.FirstFix], 0
mov [ebx+xhci_pipe.Cycle], XHCI_TRB_C
call xhci_set_dequeue
.nothing:
popad
ret
endp
; =============================================================================
; ========================== Address and packet size ==========================
; =============================================================================
; Called from usb_set_address_callback. The bus address is chosen by the
; controller itself while executing the Address Device command, so the only
; thing left to do is to remember the number the kernel has reserved: it asks
; for it back on disconnect in order to mark it free again.
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address.
proc xhci_set_device_address
movzx eax, cl
mov [ebx+xhci_pipe.Address-sizeof.xhci_pipe], eax
jmp [usbhc_api.usb_subscribe_control]
endp
; in: esi -> usb_controller, ebx -> usb_pipe. out: eax = address.
proc xhci_get_device_address
mov eax, [ebx+xhci_pipe.Address-sizeof.xhci_pipe]
ret
endp
; Called from usb_get_descr8_callback once the real packet size of the default
; control endpoint is known. On xHCI that value lives in the Endpoint Context,
; so an Evaluate Context command is needed to update it.
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size.
proc xhci_set_endpoint_packet_size
push ebx ecx edx edi
sub ebx, sizeof.xhci_pipe
if XHCI_SUPERSPEED
; For a SuperSpeed device bMaxPacketSize0 is an exponent, and the only value
; the specification allows is 9: use 512 directly instead of the raw byte.
cmp [ebx+xhci_pipe.PSIV], XHCI_PSI_SS
jb @f
mov ecx, 512
@@:
end if
mov [ebx+xhci_pipe.MaxPacket], ecx
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
mov edx, [esi+xhci_controller.InputCtx-XCD]
mov dword [edx+4], 2 ; evaluate the default control endpoint
call xhci_fill_ep_ctx
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_EVAL_CTX shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
push ebx
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
pop ebx
cmp eax, XHCI_CC_SUCCESS
jz @f
DEBUGF 1,'K : XHCI: Evaluate Context failed, code %d\n',eax
@@:
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
pop edi edx ecx ebx
jmp [usbhc_api.usb_subscribe_control]
endp
; If the descriptor that has just completed is the answer to a request for the
; hub descriptor, tell the controller that the device is a hub: it has to know
; that in order to serve the devices behind it.
; in: ebx -> usb_gtd.
proc xhci_check_hub_descriptor
pushad
cmp [ebx+usb_gtd.Callback], 0
jz .nothing
mov eax, [ebx+usb_gtd.Pipe]
mov esi, [eax+usb_pipe.Controller]
sub eax, sizeof.xhci_pipe
test [eax+xhci_pipe.Flags], XHCI_PIPE_HUBPEND
jz .nothing
and [eax+xhci_pipe.Flags], not XHCI_PIPE_HUBPEND
cmp [ebx+xhci_gtd.Status-sizeof.xhci_gtd], XHCI_CC_SUCCESS
jnz .nothing
mov edx, [eax+xhci_pipe.HubBuf]
test edx, edx
jz .nothing
cmp byte [edx+1], 29h ; bDescriptorType
jnz .nothing
or [eax+xhci_pipe.Flags], XHCI_PIPE_ISHUB
mov ebx, eax ; ebx -> xhci_pipe of the hub
movzx edi, byte [edx+2] ; bNbrPorts
movzx ebp, byte [edx+3] ; low byte of wHubCharacteristics
shr ebp, 5
and ebp, 3 ; Transaction Translator Think Time
DEBUGF 1,'K : XHCI: device on slot %d is a hub with %d ports\n',[ebx+xhci_pipe.SlotId],edi
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexLock
call xhci_clear_input_ctx
mov eax, [esi+xhci_controller.InputCtx-XCD]
mov dword [eax+4], 1 ; only the Slot Context is evaluated
mov ecx, [ebx+xhci_pipe.MaxDCI]
test ecx, ecx
jnz @f
movi ecx, 1
@@:
call xhci_fill_slot_ctx
; Patch the Slot Context with the fields that describe a hub. Only Configure
; Endpoint takes them into account, Evaluate Context would ignore them.
mov eax, [esi+xhci_controller.InputCtx-XCD]
movi ecx, 1
call xhci_context
or dword [eax], 1 shl 26 ; this device is a hub
cmp [ebx+xhci_pipe.Speed], USB_SPEED_HS
jnz @f
shl ebp, 16
or [eax+8], ebp
@@:
shl edi, 24
or [eax+4], edi ; Number of Ports
mov edx, [ebx+xhci_pipe.SlotId]
shl edx, 24
or edx, XHCI_TRB_CONFIG_EP shl 10
mov eax, [esi+xhci_controller.InputCtxPhys-XCD]
xor ebx, ebx
xor ecx, ecx
call xhci_cmd_submit
cmp eax, XHCI_CC_SUCCESS
jz @f
DEBUGF 1,'K : XHCI: cannot mark the device as a hub, code %d\n',eax
@@:
lea ecx, [esi+xhci_controller.CmdLock-XCD]
invoke MutexUnlock
.nothing:
popad
ret
endp
+135
View File
@@ -0,0 +1,135 @@
; SuperSpeed support for the xHCI driver, included from xhci.asm when
; XHCI_SUPERSPEED is enabled. The pieces too small to live here - the port
; map, the Slot Context speed, the 512-byte default control endpoint, the
; Max Burst field of the Endpoint Context - sit in the other files under
; "if XHCI_SUPERSPEED" guards; this file keeps the self-contained procedures.
;
; The kernel USB stack knows nothing about SuperSpeed, so it never learns
; about it: a SuperSpeed device is announced as a high-speed one, which also
; keeps the Transaction Translator logic away from it. The raw PORTSC speed
; identifier travels in xhci_pipe.PSIV instead and reaches everything that
; really needs it. SuperSpeed hubs are not supported: the kernel only speaks
; the USB2 hub protocol, so a device behind a USB3 hub is served by the USB2
; half of that hub at high speed.
; =============================================================================
; ============================ SuperSpeed ports ===============================
; =============================================================================
; Called from xhci_new_port for a SuperSpeed root port instead of the USB2
; reset entry point: a SuperSpeed link trains itself and the port enables
; itself on connect, reporting the speed with no reset at all. When the link
; is already up, skip straight to the reset recovery stage, after which
; xhci_port_init picks the device up; otherwise try a warm reset.
; in: esi -> usb_controller, ecx = port index.
proc xhci_ss_start_port
push eax edx
and [esi+usb_controller.ResettingHub], 0
mov [esi+usb_controller.ResettingPort], cl
push ecx
invoke GetTimerTicks
pop ecx
mov [esi+usb_controller.ResetTime], eax
mov [esi+xhci_controller.ResetStart-XCD], eax
call xhci_port_reg
mov eax, [edx]
test al, XHCI_PORT_PED
jz .warm_reset
mov [esi+usb_controller.ResettingStatus], 2
DEBUGF 1,'K : XHCI %x: SS port %d link is up, PORTSC=%x\n',esi,ecx,eax
jmp .nothing
.warm_reset:
; Connected, but the link has not come up. The Port Reset bit is set while a
; warm reset is running, so the ordinary reset-wait machinery in
; xhci_port_reset_done serves this case unchanged; the extra WRC change bit is
; acknowledged there together with the usual ones.
mov dword [edx], XHCI_PORT_PP + XHCI_PORT_WPR
mov [esi+usb_controller.ResettingStatus], 1
DEBUGF 1,'K : XHCI %x: warm-resetting port %d, PORTSC=%x\n',esi,ecx,eax
.nothing:
pop edx eax
ret
endp
; The kernel restarts pending root ports through the NewPortReset entry of
; usb_hardware_func directly, bypassing xhci_new_port; SuperSpeed ports must
; not get the USB2 reset on that path either, so the entry points here.
; in: esi -> usb_controller, ecx = port index.
proc xhci_ss_port_reset
bt [esi+xhci_controller.SSPortMask-XCD], ecx
jnc xhci_new_port.reset
call xhci_ss_start_port
ret
endp
; =============================================================================
; ===================== Endpoint Companion descriptors ========================
; =============================================================================
; Reads the SuperSpeed Endpoint Companion descriptor of a bulk endpoint and
; keeps its bMaxBurst for the Endpoint Context, allowing bursts of up to
; bMaxBurst+1 packets per transaction. Zero (no bursts) is always legal, so
; any failure just leaves the field alone. Only bulk endpoints are considered:
; a nonzero burst on a periodic endpoint would also require the Max ESIT
; Payload fields, and real interrupt endpoints do not burst anyway.
; Relies on the stack frame of usb_open_pipe exactly like xhci_init_pipe does:
; [ebp+8] is the config pipe of the device.
; in: ebx -> xhci_pipe of a non-control endpoint being opened.
proc xhci_ss_get_burst
push eax ecx edx edi
; 1. Only SuperSpeed bulk endpoints are of interest.
cmp [ebx+xhci_pipe.PSIV], XHCI_PSI_SS
jb .nothing
mov eax, [ebx+xhci_pipe.EpType]
and al, 3
cmp al, 2 ; bulk endpoint types are 2 and 6
jnz .nothing
; 2. Find the configuration data kept by the kernel behind the device
; descriptor; it holds the endpoint descriptors with their companions.
mov eax, [ebp+8]
mov eax, [eax+usb_pipe.DeviceData]
test eax, eax
jz .nothing
movzx edx, [eax+usb_device_data.DeviceDescrSize]
mov edi, [eax+usb_device_data.ConfigDataSize]
lea ecx, [eax+edx+usb_device_data.DeviceDescriptor]
add edi, ecx ; edi -> end of the configuration data
; 3. Reconstruct bEndpointAddress from the Device Context Index.
mov edx, [ebx+xhci_pipe.DCI]
shr edx, 1
test [ebx+xhci_pipe.Flags], XHCI_PIPE_IN
jz @f
or dl, 80h
@@:
; 4. Walk the descriptors to the one of this endpoint.
.walk:
lea eax, [ecx+2]
cmp eax, edi
ja .nothing
movzx eax, byte [ecx] ; bLength
test eax, eax
jz .nothing ; malformed data, stop
cmp byte [ecx+1], 5 ; an endpoint descriptor?
jnz .advance
cmp [ecx+2], dl ; bEndpointAddress
jnz .advance
; 5. The companion descriptor (type 30h) immediately follows its endpoint.
add ecx, eax
lea eax, [ecx+3]
cmp eax, edi
ja .nothing
cmp byte [ecx+1], 30h ; SuperSpeed Endpoint Companion
jnz .nothing
movzx eax, byte [ecx+2] ; bMaxBurst
cmp eax, 15
ja .nothing
mov [ebx+xhci_pipe.MaxBurst], eax
DEBUGF 1,'K : XHCI: slot %d dci %d bursts %d+1 packets\n',[ebx+xhci_pipe.SlotId],[ebx+xhci_pipe.DCI],eax
jmp .nothing
.advance:
add ecx, eax
jmp .walk
.nothing:
pop edi edx ecx eax
ret
endp
File diff suppressed because it is too large. Load diff
+4 -1
View File
@@ -1721,7 +1721,8 @@ endp
; out: eax = 1 if the interrupt came from this controller, 0 otherwise
align 4
ahci_irq_handler:
mov esi, [esp + 4]
push ebx esi edi
mov esi, [esp + 12 + 4]
test esi, esi
jz .not_our
mov edx, [esi + AHCI_CTR.abar]
@@ -1786,9 +1787,11 @@ ahci_irq_handler:
@@:
pop eax
mov eax, 1
pop edi esi ebx
ret
.not_our:
xor eax, eax
pop edi esi ebx
ret
+15 -3
View File
@@ -1489,19 +1489,31 @@ dyndisk_handler:
; 12. The fs operation has specified some partition.
push edx ecx
xor eax, eax
mov ecx, eax
lodsb
@@:
lea ecx, [ecx*4 + ecx]
shl ecx, 1
sub eax, '0'
jz .dyndisk_cleanup
jb .dyndisk_cleanup
cmp eax, 10
jnc .dyndisk_cleanup
mov ecx, eax
add ecx, eax
cmp ecx, MAX_NUM_PARTITIONS
ja .dyndisk_cleanup
lodsb
cmp eax, '/'
jz @f
test eax, eax
jnz .dyndisk_cleanup
jnz @b
dec esi
@@:
test ecx, ecx
jz .dyndisk_cleanup
cmp byte [esi], 0
jnz @f
; partition info
+76 -16
View File
@@ -2507,7 +2507,7 @@ dword-значение цвета 0x00RRGGBB
* иначе eax = TID - идентификатор потока
---------------------- Константы для регистров: ----------------------
eax - SF_CREATE_THREAD (51) /
eax - SF_THREAD_CONTROL (51) /
ebx - SSF_CREATE_THREAD (1), SSF_GET_CURR_THREAD_SLOT (2),
SSF_GET_THREAD_PRIORITY (3), SSF_SET_THREAD_PRIORITY (4)
@@ -4098,6 +4098,9 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* подфункция 7 - запуск программы
* подфункция 8 - удаление файла/папки
* подфункция 9 - создание папки
* подфункция 10 - переименование/перемещение
* подфункция 11 - создание симлинка
* подфункция 12 - чтение симлинка
Для CD-приводов в связи с аппаратными ограничениями доступны
только подфункции 0,1,5 и 7, вызов других подфункций завершится
ошибкой с кодом 2.
@@ -4112,7 +4115,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
[ebx] - SSF_READ_FILE (0), SSF_READ_FOLDER (1), SSF_CREATE_FILE (2),
SSF_WRITE_FILE (3), SSF_SET_END (4), SSF_GET_INFO (5),
SSF_SET_INFO (6), SSF_START_APP (7), SSF_DELETE (8),
SSF_CREATE_FOLDER (9)
SSF_CREATE_FOLDER (9), SSF_RENAME (10), SSF_CREATE_SYMLINK (11),
SSF_READ_SYMLINK (12)
======================================================================
= Функция 70, подфункция 0 - чтение файла с поддержкой длинных имён. =
======================================================================
@@ -4464,6 +4468,62 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* Формирование нового пути отличается от общих правил:
относительный путь относится к папке целевого файла (или папки),
абсолютный путь считается от корня раздела.
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_RENAME (10)
======================================================================
=========== Функция 70, подфункция 11 - создание симлинка. ===========
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 11 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: указатель на строку с целевым путём
* +20 = +0x14: путь, правила формирования имён указаны в общем
описании (путь ссылки)
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx разрушается
Замечания:
* Родительская папка должна существовать.
* Для CD функция не поддерживается (возвращает код ошибки 2).
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_CREATE_SYMLINK (11)
======================================================================
============ Функция 70, подфункция 12 - чтение симлинка. ============
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 12 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: размер буфера в байтах
* +16 = +0x10: dword: указатель на буфер для целевого пути
* +20 = +0x14: путь, правила формирования имён указаны в общем
описании (путь ссылки)
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx = число байт, записанных в буфер
Замечания:
* Функция не следует по симлинку; она читает целевой путь,
на который указывает симлинк.
* Целевой путь всегда завершается нулём, в том числе при обрезании;
записывается не более (размер буфера - 1) байт пути.
* Значение в ebx включает завершающий 0, как в подфункции 2
функции 30.
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_SYMLINK (12)
======================================================================
========== Функция 71 - установить заголовок окна программы ==========
======================================================================
@@ -5059,8 +5119,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* eax = дескриптор фьютекса, 0 при ошибке
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_CREATE (0)
eax - SF_POSIX (77)
ebx - SSF_FUTEX_CREATE (0)
======================================================================
============= Функция 77, подфункция 1, Удалить фьютекс. =============
======================================================================
@@ -5074,8 +5134,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* Ядро автоматически удаляет фьютексы при завершении процесса.
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_DESTROY (1)
eax - SF_POSIX (77)
ebx - SSF_FUTEX_DESTROY (1)
======================================================================
================= Функция 77, подфункция 2, Ожидать. =================
======================================================================
@@ -5091,8 +5151,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
-2 - контрольное значение фьютекса не соответствует
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_WAIT (2)
eax - SF_POSIX (77)
ebx - SSF_FUTEX_WAIT (2)
======================================================================
================ Функция 77, подфункция 3, Разбудить. ================
======================================================================
@@ -5105,8 +5165,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* eax = количество разбуженых
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_WAKE (3)
eax - SF_POSIX (77)
ebx - SSF_FUTEX_WAKE (3)
======================================================================
Замечания:
* Подфункции 4-7 зарезервированы и сейчас возвращают -1.
@@ -5128,8 +5188,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* Поддерживаются только pipe-дескрипторы.
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_FILE_READ (10)
eax - SF_POSIX (77)
ebx - SSF_FD_READ (10)
======================================================================
======== Функция 77, подфункция 11, Записать из буфера в файл. =======
@@ -5148,8 +5208,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* Поддерживаются только pipe-дескрипторы.
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_FILE_WRITE (11)
eax - SF_POSIX (77)
ebx - SSF_FD_WRITE (11)
======================================================================
=========== Функция 77, подфункция 13, Создать новый pipe. ===========
@@ -5173,8 +5233,8 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
- дескриптором записи.
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_PIPE_CREATE (13)
eax - SF_POSIX (77)
ebx - SSF_FD_PIPE2 (13)
======================================================================
========== Функция -1 - завершить выполнение потока/процесса =========
+74 -16
View File
@@ -2492,7 +2492,7 @@ Returned value:
* otherwise eax = TID - thread identifier
---------------------- Constants for registers: ----------------------
eax - SF_CREATE_THREAD (51)
eax - SF_THREAD_CONTROL (51)
ebx - SSF_CREATE_THREAD (1), SSF_GET_CURR_THREAD_SLOT (2),
SSF_GET_THREAD_PRIORITY (3), SSF_SET_THREAD_PRIORITY (4)
======================================================================
@@ -4060,6 +4060,9 @@ Available subfunctions:
* subfunction 7 - start application
* subfunction 8 - delete file/folder
* subfunction 9 - create folder
* subfunction 10 - rename/move
* subfunction 11 - create symlink
* subfunction 12 - read symlink
For CD-drives due to hardware limitations only subfunctions
0,1,5 and 7 are available, other subfunctions return error
with code 2.
@@ -4073,7 +4076,8 @@ is called for corresponding device.
[ebx] - SSF_READ_FILE (0), SSF_READ_FOLDER (1), SSF_CREATE_FILE (2),
SSF_WRITE_FILE (3), SSF_SET_END (4), SSF_GET_INFO (5),
SSF_SET_INFO (6), SSF_START_APP (7), SSF_DELETE (8),
SSF_CREATE_FOLDER (9)
SSF_CREATE_FOLDER (9), SSF_RENAME (10), SSF_CREATE_SYMLINK (11),
SSF_READ_SYMLINK (12)
======================================================================
=== Function 70, subfunction 0 - read file with long names support. ==
======================================================================
@@ -4423,6 +4427,60 @@ Remarks:
* New path forming differs from general rules:
relative path relates to the target's parent folder,
absolute path relates to the partition's root folder.
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_RENAME (10)
======================================================================
=========== Function 70, subfunction 11 - create symlink. ============
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 11 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: pointer to the target path string
* +20 = +0x14: path, general rules of names forming (link path)
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx destroyed
Remarks:
* The parent folder must already exist.
* The function is not supported for CD (returns error code 2).
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_CREATE_SYMLINK (11)
======================================================================
============ Function 70, subfunction 12 - read symlink. =============
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 12 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: buffer size in bytes
* +16 = +0x10: dword: pointer to buffer for target path
* +20 = +0x14: path, general rules of names forming (link path)
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx = number of bytes written to the buffer
Remarks:
* The function does not follow the symlink; it reads the target path
that the symlink points to.
* The target path is always terminated with 0, even when truncated;
at most (buffer size - 1) path bytes are written.
* The value returned in ebx includes the terminating 0, as in
subfunction 2 of function 30.
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_SYMLINK (12)
======================================================================
================== Function 71 - set window caption ==================
======================================================================
@@ -5273,8 +5331,8 @@ Returned value:
* eax = futex handle, 0 on error
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_CREATE (0)
eax - SF_POSIX (77)
ebx - SSF_FUTEX_CREATE (0)
======================================================================
========= Function 77, Subfunction 1, Destroy futex object ===========
======================================================================
@@ -5289,8 +5347,8 @@ Remarks:
terminates.
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_DESTROY (1)
eax - SF_POSIX (77)
ebx - SSF_FUTEX_DESTROY (1)
======================================================================
=============== Function 77, Subfunction 2, Futex wait ===============
======================================================================
@@ -5306,8 +5364,8 @@ Returned value:
-2 - futex control value doesn't match
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_WAIT (2)
eax - SF_POSIX (77)
ebx - SSF_FUTEX_WAIT (2)
======================================================================
=============== Function 77, Subfunction 3, Futex wake ===============
======================================================================
@@ -5320,8 +5378,8 @@ Returned value:
* eax = number of waiters that were woken up
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_WAKE (3)
eax - SF_POSIX (77)
ebx - SSF_FUTEX_WAKE (3)
======================================================================
Remarks:
* Subfunctions 4-7 are reserved and currently return -1.
@@ -5343,8 +5401,8 @@ Remarks:
* Only pipe descriptors are supported.
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_FILE_READ (10)
eax - SF_POSIX (77)
ebx - SSF_FD_READ (10)
======================================================================
=========== Function 77, Subfunction 11, Write to file. =============
======================================================================
@@ -5362,8 +5420,8 @@ Remarks:
* Only pipe descriptors are supported.
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_FILE_WRITE (11)
eax - SF_POSIX (77)
ebx - SSF_FD_WRITE (11)
======================================================================
========== Function 77, Subfunction 13, Create pipe. ================
======================================================================
@@ -5381,8 +5439,8 @@ Remarks:
write handle.
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_PIPE_CREATE (13)
eax - SF_POSIX (77)
ebx - SSF_FD_PIPE2 (13)
======================================================================
=== Function 80 - file system interface with parameter of encoding ===
======================================================================
+1034 -72
View File
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -2405,11 +2405,12 @@ fat_Write:
; hd_extend_file can return three error codes: FAT table error, device error or disk full.
; First two cases are fatal errors, in third case we may write some data
cmp al, ERROR_DISK_FULL
jnz @f
jnz .noWrite
; correct number of bytes to write
mov ecx, [edi+28]
cmp ecx, ebx
ja .length_ok
.noWrite:
push 0
.ret:
pop eax eax eax ecx ecx
+13 -1
View File
@@ -182,10 +182,22 @@ proc file_system_is_operation_safe stdcall, inf_struct_ptr: dword
.case6:
cmp dword [ebx], 6
jnz .switch_none
jnz .case11
mov ecx, 32
jmp .end_switch
.case11:
cmp dword [ebx], 11
jnz .case12
stdcall is_string_userspace, edx
jmp .ret
.case12:
cmp dword [ebx], 12
jnz .switch_none
mov ecx, dword [ebx + 12]
jmp .end_switch
.switch_none:
cmp ecx, ecx
jmp .ret
+2 -1
View File
@@ -253,9 +253,10 @@ UTF16to8_string:
UTF16to8:
; in:
; eax = UTF-16 char
; ax = UTF-16 char
; edi -> buffer for UTF-8 char (increasing)
; ecx = byte counter (decreasing)
movzx eax, ax
dec ecx
js .ret
cmp eax, 80h
+6
View File
@@ -48,6 +48,10 @@ dtext:
add esp, 28
ret
.nomem:
add esp, 40
ret
.redirect:
mov ebp, [edi]
add edi, 8
@@ -81,6 +85,8 @@ dtext:
mov [esp+32], eax
imul ebp, eax
stdcall kernel_alloc, ebp
test eax, eax
jz .nomem
mov ecx, ebp
shr ecx, 2
mov [esp+36], eax
+53 -6
View File
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2026. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; IPv4.INC ;;
@@ -765,9 +765,9 @@ ipv4_output_raw:
push ebx ; push the mac
push ax
inc [IPv4_packets_tx + 4*edi]
inc [IPv4_packets_tx + edi]
mov ax, ETHER_PROTO_IPv4
mov ebx, [net_device_list + 4*edi]
mov ebx, [net_device_list + edi]
mov ecx, [esp + 6 + 4]
add ecx, sizeof.IPv4_header
mov edx, esp
@@ -951,7 +951,7 @@ endp
; edi = device number*4 ;
; ;
; DESTROYED: ;
; ecx ;
; ebx, ecx ;
; ;
;-----------------------------------------------------------------;
align 4
@@ -964,6 +964,7 @@ ipv4_route:
cmp eax, 0xffffffff
je .broadcast
; Check for on-link
xor edi, edi
.loop:
mov ebx, [IPv4_address + edi]
@@ -978,9 +979,55 @@ ipv4_route:
cmp edi, 4*NET_DEVICES_MAX
jb .loop
mov eax, [IPv4_gateway + 4] ; TODO: let user (or a user space daemon) configure default route
; no on-link match, find first device with a gateway
mov edi, 4 ; skip loopback device
.loop_gw:
cmp [IPv4_gateway + edi], 0
jne .found_gw
add edi, 4
cmp edi, 4*NET_DEVICES_MAX
jb .loop_gw
jmp .loopback ; no gateway found, fall-back to loopback device
.found_gw:
mov eax, [IPv4_gateway + edi]
jmp .got_it
.broadcast:
mov edi, 4 ; TODO: same as above
; broadcast: we will do our best without full routing..
; find the first non loopback device which has an active link without IP address
mov edi, 4 ; skip loopback device
.bc_loop1:
mov ebx, [net_device_list + edi]
test ebx, ebx
jz @f
cmp [ebx + NET_DEVICE.link_state], 0
je @f
cmp [IPv4_address + edi], 0
je .got_it
@@:
add edi, 4
cmp edi, 4*NET_DEVICES_MAX
jb .bc_loop1
; If there is no such device, try the one with active link and IP address
mov edi, 4 ; skip loopback device
.bc_loop2:
mov ebx, [net_device_list + edi]
test ebx, ebx
jz @f
cmp [ebx + NET_DEVICE.link_state], 0
jne .got_it
@@:
add edi, 4
cmp edi, 4*NET_DEVICES_MAX
jb .bc_loop2
; jmp .loopback ; no gateway found, fall-back to loopback device
.loopback:
xor edi, edi ; nowhere to go for now.. route it to the loopback device
.got_it:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
test edx, edx
+2 -4
View File
@@ -780,8 +780,6 @@ socket_close:
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
jne .free
test [eax + SOCKET.state], SS_ISCONNECTED
jz @f
test [eax + SOCKET.state], SS_ISDISCONNECTING
jnz @f
call tcp_disconnect
@@ -2126,11 +2124,11 @@ socket_free:
mov ebx, eax
cmp [eax + STREAM_SOCKET.rcv.start_ptr], 0
je @f
stdcall free_kernel_space, [eax + STREAM_SOCKET.rcv.start_ptr]
stdcall kernel_free, [eax + STREAM_SOCKET.rcv.start_ptr]
@@:
cmp [ebx + STREAM_SOCKET.snd.start_ptr], 0
je @f
stdcall free_kernel_space, [ebx + STREAM_SOCKET.snd.start_ptr]
stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr]
@@:
mov eax, ebx
.no_stream:
+1 -1
View File
@@ -118,7 +118,7 @@ SS_MORETOCOME = 0x4000
SS_BLOCKED = 0x8000
SOCKET_BUFFER_SIZE = 4096*8 ; must be 4096*(power of 2) where 'power of 2' is at least 8
SOCKET_BUFFER_SIZE = 4096*32 ; must be 4096*(power of 2) where 'power of 2' is at least 8
MAX_backlog = 20 ; maximum backlog for stream sockets
; Error Codes
+7 -2
View File
@@ -355,9 +355,14 @@ endl
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Got window scale option\n"
or [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
; remember the peer's scale factor; it is applied to SND_SCALE when the
; connection is established (together with our RCV_SCALE)
lodsb
mov [ebx + TCP_SOCKET.SND_SCALE], al
;;;;; TODO
cmp al, TCP_max_winshift
jbe .wscale_capped
mov al, TCP_max_winshift
.wscale_capped:
mov [ebx + TCP_SOCKET.requested_s_scale], al
@@:
jmp .opt_loop
+4 -4
View File
@@ -320,12 +320,12 @@ tcp_respond:
stosb
mov eax, SOCKET_BUFFER_SIZE
sub eax, [esi + STREAM_SOCKET.rcv.size]
cmp eax, TCP_max_win
mov cl, [esi + TCP_SOCKET.RCV_SCALE]
shr eax, cl ; scale first, then clamp to the
cmp eax, TCP_max_win ; 16-bit field maximum
jbe .lessthanmax
mov eax, TCP_max_win
.lessthanmax:
mov cl, [esi + TCP_SOCKET.RCV_SCALE]
shr eax, cl
xchg al, ah
stosw ; window
@@ -488,7 +488,7 @@ tcp_set_persist:
; Start/restart persistence timer.
tcpt_rangeset [eax + TCP_SOCKET.timer_persist], ebx, TCP_time_pers_min, TCP_time_pers_max
or [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
or [eax + TCP_SOCKET.timer_flags], timer_flag_persist
pop ebx
cmp [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift
+4 -4
View File
@@ -111,13 +111,13 @@ proc tcp_timer_640ms
DEBUGF DEBUG_NETWORK_VERBOSE, "socket %x: Keepalive expired\n", eax
cmp [eax + TCP_SOCKET.state], TCPS_ESTABLISHED
ja .dont_kill
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
jae .dont_kill
push eax
push [eax + SOCKET.NextPtr]
call tcp_disconnect
pop eax
jmp .loop
jmp .check_only
.dont_kill:
test [eax + SOCKET.options], SO_KEEPALIVE
+9 -9
View File
@@ -125,7 +125,7 @@ SF_STYLE_SETTINGS=48
SSF_SET_FONT_SIZE=12
SF_APM=49
SF_SET_WINDOW_SHAPE=50
SF_CREATE_THREAD=51
SF_THREAD_CONTROL=51
SSF_CREATE_THREAD=1
SSF_GET_CURR_THREAD_SLOT=2
SSF_GET_THREAD_PRIORITY=3
@@ -281,14 +281,14 @@ SF_NETWORK_PROTOCOL=76
SSF_ARP_DEL_ENTRY=50005h
SSF_ARP_SEND_ANNOUNCE=50006h
SSF_ARP_CONFLICTS_COUNT=50007h
SF_FUTEX=77
SSF_CREATE=0
SSF_DESTROY=1
SSF_WAIT=2
SSF_WAKE=3
SSF_FILE_READ=10
SSF_FILE_WRITE=11
SSF_PIPE_CREATE=13
SF_POSIX=77
SSF_FUTEX_CREATE=0
SSF_FUTEX_DESTROY=1
SSF_FUTEX_WAIT=2
SSF_FUTEX_WAKE=3
SSF_FD_READ=10
SSF_FD_WRITE=11
SSF_FD_PIPE2=13
; File system errors:
FSERR_SUCCESS=0
+1 -1
View File
@@ -1111,7 +1111,7 @@ end if
mov dword [edx+8],ebx
mov dword [edx+4],ecx
mov dword [edx],Kolibri_ThreadFinish
mov eax,SF_CREATE_THREAD
mov eax,SF_THREAD_CONTROL
mov ebx,1
mov ecx,@Kolibri@ThreadMain$qpvt1
int 0x40
+2
View File
@@ -0,0 +1,2 @@
@fasm free3d04.asm free3d04
if not exist free3d04 ( @pause )
-5
View File
@@ -1,5 +0,0 @@
@erase lang.inc
@echo lang fix en_US >lang.inc
@fasm free3d04.asm free3d04
@erase lang.inc
@pause
-5
View File
@@ -1,5 +0,0 @@
@erase lang.inc
@echo lang fix ru_RU >lang.inc
@fasm free3d04.asm free3d04
@erase lang.inc
@pause
+49 -10
View File
@@ -9,9 +9,10 @@
;
; Compile with FASM for Menuet (requires .INC files - see DATA Section)
;
; Willow - greatly srinked code size by using GIF texture and FPU to calculate sine table
; Willow - greatly srinked code size by using packed texture and FPU to calculate sine table
;
; !!!! Don't use GIF_LITE.INC in your apps - it's modified for FREE3D !!!!
; Textures are stored as a single 64x512 PNG embedded into the binary and
; decoded at startup with libimg.
;
; Heavyiron - new 0-function of drawing window from kolibri (do not work correctly with menuet)
@@ -38,15 +39,17 @@ use32
dd APP_MEM;0x100000 ; memory for app
dd APP_MEM;0x100000 ; esp
dd 0x0 , 0x0 ; I_Param , I_Icon
include 'lang.inc'
include '..\..\macros.inc'
COLOR_ORDER equ OTHER
include 'gif_lite.inc'
include '..\..\proc32.inc'
include '..\..\dll.inc'
include '..\..\develop\libraries\libs-dev\libimg\libimg.inc'
START: ; start of execution
mov esi,textures
mov edi,ceil-8
call ReadGIF
mcall 68,11 ; init heap, libimg needs it
stdcall dll.Load,@IMPORT
test eax,eax
jnz finish
call load_textures
mov esi,sinus
mov ecx,360*10
fninit
@@ -291,6 +294,34 @@ m_right: ; turn right
mcall
; *********************************************
; ******* LOAD TEXTURES ********
; *********************************************
; Decodes the embedded 64x512 PNG (8 stacked 64x64 tiles) into the raw
; 0x00RRGGBB texture bank at [ceil].
load_textures:
invoke img.decode,textures,textures.size,0
test eax,eax
jz finish
mov ebx,eax
invoke img.convert,ebx,0,Image.bpp32,0,0
push eax
invoke img.destroy,ebx
pop ebx
test ebx,ebx
jz finish
mov esi,[ebx+Image.Data]
mov edi,ceil
mov ecx,TEX_SIZE*8/4
.copy:
lodsd
and eax,0x00FFFFFF ; drop alpha, the renderer stores 32 bit dwords
stosd ; into a 24 bit image buffer
loop .copy
invoke img.destroy,ebx
ret
; *********************************************
; ******* WINDOW DEFINITIONS AND DRAW ********
; *********************************************
@@ -980,13 +1011,21 @@ dd 0x0001FFFF ; initial player position * 0xFFFF
vpy:
dd 0x0001FFFF
title db 'FISHEYE RAYCASTING ENGINE ETC. FREE3D',0
title db 'Fisheye Raycasting Engine Etc. FREE3D',0
sindegree dd 0.0
sininc dd 0.0017453292519943295769236907684886
sindiv dd 6553.5
textures:
file 'texture.gif'
file 'texture.png'
.size = $ - textures
align 16
@IMPORT:
library libimg , 'libimg.obj'
import libimg , libimg.init , 'lib_init' , img.decode , 'img_decode' , img.convert , 'img_convert', img.destroy , 'img_destroy'
align 4
-487
View File
@@ -1,487 +0,0 @@
; GIF LITE v3.0 by Willow
; Written in pure assembler by Ivushkin Andrey aka Willow
; Modified by Diamond
;
; This include file will contain functions to handle GIF image format
;
; Created: August 15, 2004
; Last changed: June 24, 2007
; Requires kglobals.inc (iglobal/uglobal macro)
; (program must 'include "kglobals.inc"' and say 'IncludeUGlobal'
; somewhere in uninitialized data area).
; Configuration: [changed from program which includes this file]
; 1. The constant COLOR_ORDER: must be one of
; PALETTE - for 8-bit image with palette (sysfunction 65)
; MENUETOS - for MenuetOS and KolibriOS color order (sysfunction 7)
; OTHER - for standard color order
; 2. Define constant GIF_SUPPORT_INTERLACED if you want to support interlaced
; GIFs.
; 3. Single image mode vs multiple image mode:
; if the program defines the variable 'gif_img_count' of type dword
; somewhere, ReadGIF will enter multiple image mode: gif_img_count
; will be initialized with image count, output format is GIF_list,
; the function GetGIFinfo retrieves Nth image info. Otherwise, ReadGIF
; uses single image mode: exit after end of first image, output is
; <dd width,height, times width*height[*3] db image>
if ~ (COLOR_ORDER in <PALETTE,MENUETOS,OTHER>)
; This message may not appear under MenuetOS, so watch...
display 'Please define COLOR_ORDER: PALETTE, MENUETOS or OTHER',13,10
end if
if defined gif_img_count
; virtual structure, used internally
struct GIF_list
NextImg rd 1
Left rw 1
Top rw 1
Width rw 1
Height rw 1
Delay rd 1
Displacement rd 1 ; 0 = not specified
; 1 = do not dispose
; 2 = restore to background color
; 3 = restore to previous
if COLOR_ORDER eq PALETTE
Image rd 1
end if
ends
struct GIF_info
Left rw 1
Top rw 1
Width rw 1
Height rw 1
Delay rd 1
Displacement rd 1
if COLOR_ORDER eq PALETTE
Palette rd 1
end if
ends
; ****************************************
; FUNCTION GetGIFinfo - retrieve Nth image info
; ****************************************
; in:
; esi - pointer to image list header
; ecx - image_index (0...img_count-1)
; edi - pointer to GIF_info structure to be filled
; out:
; eax - pointer to RAW data, or 0, if error
GetGIFinfo:
push esi ecx edi
xor eax,eax
jecxz .eloop
.lp:
mov esi,[esi]
test esi,esi
jz .error
loop .lp
.eloop:
lodsd
movsd
movsd
movsd
movsd
if COLOR_ORDER eq PALETTE
lodsd
mov [edi],esi
else
mov eax,esi
end if
.error:
pop edi ecx esi
ret
end if
_null fix 0x1000
; ****************************************
; FUNCTION ReadGIF - unpacks GIF image
; ****************************************
; in:
; esi - pointer to GIF file in memory
; edi - pointer to output image list
; out:
; eax - 0, all OK;
; eax - 1, invalid signature;
; eax >=8, unsupported image attributes
;
ReadGIF:
push esi edi
mov [.cur_info],edi
xor eax,eax
mov [.globalColor],eax
if defined gif_img_count
mov [gif_img_count],eax
mov [.anim_delay],eax
mov [.anim_disp],eax
end if
inc eax
cmp dword[esi],'GIF8'
jne .ex ; signature
mov ecx,[esi+0xa]
add esi,0xd
mov edi,esi
test cl,cl
jns .nextblock
mov [.globalColor],esi
call .Gif_skipmap
.nextblock:
cmp byte[edi],0x21
jne .noextblock
inc edi
if defined gif_img_count
cmp byte[edi],0xf9 ; Graphic Control Ext
jne .no_gc
movzx eax,word [edi+3]
mov [.anim_delay],eax
mov al,[edi+2]
shr al,2
and eax,7
mov [.anim_disp],eax
add edi,7
jmp .nextblock
.no_gc:
end if
inc edi
.block_skip:
movzx eax,byte[edi]
lea edi,[edi+eax+1]
test eax,eax
jnz .block_skip
jmp .nextblock
.noextblock:
mov al,8
cmp byte[edi],0x2c ; image beginning
jne .ex
if defined gif_img_count
inc [gif_img_count]
end if
inc edi
mov esi,[.cur_info]
if defined gif_img_count
add esi,4
end if
xchg esi,edi
if defined GIF_SUPPORT_INTERLACED
movzx ecx,word[esi+4]
mov [.width],ecx
movzx eax,word[esi+6]
imul eax,ecx
if ~(COLOR_ORDER eq PALETTE)
lea eax,[eax*3]
end if
mov [.img_end],eax
inc eax
mov [.row_end],eax
and [.pass],0
test byte[esi+8],40h
jz @f
if ~(COLOR_ORDER eq PALETTE)
lea ecx,[ecx*3]
end if
mov [.row_end],ecx
@@:
end if
if defined gif_img_count
movsd
movsd
mov eax,[.anim_delay]
stosd
mov eax,[.anim_disp]
stosd
else
movzx eax,word[esi+4]
stosd
movzx eax,word[esi+6]
stosd
add esi,8
end if
push edi
mov ecx,[esi]
inc esi
test cl,cl
js .uselocal
push [.globalColor]
mov edi,esi
jmp .setPal
.uselocal:
call .Gif_skipmap
push esi
.setPal:
movzx ecx,byte[edi]
inc ecx
mov [.codesize],ecx
dec ecx
if ~(COLOR_ORDER eq PALETTE)
pop [.Palette]
end if
lea esi,[edi+1]
mov edi,.gif_workarea
xor eax,eax
lodsb ; eax - block_count
add eax,esi
mov [.block_ofs],eax
mov [.bit_count],8
mov eax,1
shl eax,cl
mov [.CC],eax
mov ecx,eax
inc eax
mov [.EOI],eax
mov eax, _null shl 16
.filltable:
stosd
inc eax
loop .filltable
if COLOR_ORDER eq PALETTE
pop eax
pop edi
push edi
scasd
push esi
mov esi,eax
mov ecx,[.CC]
@@:
lodsd
dec esi
bswap eax
shr eax,8
stosd
loop @b
pop esi
pop eax
mov [eax],edi
else
pop edi
end if
if defined GIF_SUPPORT_INTERLACED
mov [.img_start],edi
add [.img_end],edi
add [.row_end],edi
end if
.reinit:
mov edx,[.EOI]
inc edx
push [.codesize]
pop [.compsize]
call .Gif_get_sym
cmp eax,[.CC]
je .reinit
call .Gif_output
.cycle:
movzx ebx,ax
call .Gif_get_sym
cmp eax,edx
jae .notintable
cmp eax,[.CC]
je .reinit
cmp eax,[.EOI]
je .end
call .Gif_output
.add:
mov dword [.gif_workarea+edx*4],ebx
cmp edx,0xFFF
jae .cycle
inc edx
bsr ebx,edx
cmp ebx,[.compsize]
jne .noinc
inc [.compsize]
.noinc:
jmp .cycle
.notintable:
push eax
mov eax,ebx
call .Gif_output
push ebx
movzx eax,bx
call .Gif_output
pop ebx eax
jmp .add
.end:
if defined GIF_SUPPORT_INTERLACED
mov edi,[.img_end]
end if
if defined gif_img_count
mov eax,[.cur_info]
mov [eax],edi
mov [.cur_info],edi
add esi,2
xchg esi,edi
.nxt:
cmp byte[edi],0
jnz .continue
inc edi
jmp .nxt
.continue:
cmp byte[edi],0x3b
jne .nextblock
xchg esi,edi
and dword [eax],0
end if
xor eax,eax
.ex:
pop edi esi
ret
.Gif_skipmap:
; in: ecx - image descriptor, esi - pointer to colormap
; out: edi - pointer to area after colormap
and ecx,111b
inc ecx ; color map size
mov ebx,1
shl ebx,cl
lea ebx,[ebx*2+ebx]
lea edi,[esi+ebx]
ret
.Gif_get_sym:
mov ecx,[.compsize]
push ecx
xor eax,eax
.shift:
ror byte[esi],1
rcr eax,1
dec [.bit_count]
jnz .loop1
inc esi
cmp esi,[.block_ofs]
jb .noblock
push eax
xor eax,eax
lodsb
test eax,eax
jnz .nextbl
mov eax,[.EOI]
sub esi,2
add esp,8
jmp .exx
.nextbl:
add eax,esi
mov [.block_ofs],eax
pop eax
.noblock:
mov [.bit_count],8
.loop1:
loop .shift
pop ecx
rol eax,cl
.exx:
xor ecx,ecx
ret
.Gif_output:
push esi eax edx
mov edx,.gif_workarea
.next:
push word[edx+eax*4]
mov ax,word[edx+eax*4+2]
inc ecx
cmp ax,_null
jnz .next
shl ebx,16
mov bx,[esp]
.loop2:
pop ax
if COLOR_ORDER eq PALETTE
stosb
else
lea esi,[eax+eax*2]
add esi,[.Palette]
if COLOR_ORDER eq MENUETOS
mov esi,[esi]
bswap esi
shr esi,8
mov [edi],esi
add edi,3
else
movsb
movsb
movsb
mov byte [edi],0
inc edi
end if
end if
if defined GIF_SUPPORT_INTERLACED
cmp edi,[.row_end]
jb .norowend
mov eax,[.width]
if ~(COLOR_ORDER eq PALETTE)
lea eax,[eax*3]
end if
push eax
sub edi,eax
add eax,eax
cmp [.pass],3
jz @f
add eax,eax
cmp [.pass],2
jz @f
add eax,eax
@@:
add edi,eax
pop eax
cmp edi,[.img_end]
jb .nextrow
mov edi,[.img_start]
inc [.pass]
add edi,eax
cmp [.pass],3
jz @f
add edi,eax
cmp [.pass],2
jz @f
add edi,eax
add edi,eax
@@:
.nextrow:
add eax,edi
mov [.row_end],eax
xor eax,eax
.norowend:
end if
loop .loop2
pop edx eax esi
ret
uglobal
align 4
ReadGIF.globalColor rd 1
ReadGIF.cur_info rd 1 ; image table pointer
ReadGIF.codesize rd 1
ReadGIF.compsize rd 1
ReadGIF.bit_count rd 1
ReadGIF.CC rd 1
ReadGIF.EOI rd 1
if ~(COLOR_ORDER eq PALETTE)
ReadGIF.Palette rd 1
end if
ReadGIF.block_ofs rd 1
if defined GIF_SUPPORT_INTERLACED
ReadGIF.row_end rd 1
ReadGIF.img_end rd 1
ReadGIF.img_start rd 1
ReadGIF.pass rd 1
ReadGIF.width rd 1
end if
if defined gif_img_count
ReadGIF.anim_delay rd 1
ReadGIF.anim_disp rd 1
end if
ReadGIF.gif_workarea rb 16*1024
endg
+4 -4
View File
@@ -10,11 +10,11 @@ By Dieter Marfurt
--------------------------------------------
Format of texture include files:
Format of the texture file:
dd 0x00RRGGBB,0x00RRGGBB....
for 64*64 pixels.
texture.png - a 64*512 image holding the 8 textures of 64*64 pixels
stacked vertically. It is embedded into the binary and decoded at
startup with libimg.
Have fun!
Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+1 -1
View File
@@ -1067,7 +1067,7 @@ end if
mov dword [edx+8],ebx
mov dword [edx+4],ecx
mov dword [edx],Kolibri_ThreadFinish
mov eax,SF_CREATE_THREAD
mov eax,SF_THREAD_CONTROL
mov ebx,1
mov ecx,@Kolibri@ThreadMain$qpvt1
int 0x40
+29
View File
@@ -0,0 +1,29 @@
Компилятор XD Pascal, [оригинал проекта](https://github.com/vtereshkov/xdpw), автор оригинала Василий Терешков.
В [архиве](./release) компилятор и исходники для `xdpw_2026`(версия для Windows) и `xdpk`(версия для KolibriOS).
Компилятор также компилирует сам себя из-под KolibriOS.
Размер сжатого компилятора менее 30 килобайтов.
В папке `xdpk/projects` находятся примеры, также там находится сам компилятор под KolibriOS(`xdpk/projects/Compiler`).
Чтобы собрать какой-нибудь пример, нужно просто зайти из-под KolibriOS в папку с примером и запустить файл `MAKE.SH`.
Скомпилированное приложение должно появиться в той же папке с примером(если нет, то нажмите "обновить"(F5) в файловом менеджере).
А для сборки из-под Windows нужно запустить файл `make.bat`.
Компиляция:
* "xdpw_2026/xdpw.exe" — компилирует из-под Windows приложения для Windows
* "xdpk/xdpk.exe" — компилирует из-под Windows приложения для KolibriOS
* "xdpk/xdpk.kex" — компилирует из-под KolibriOS приложения для KolibriOS
Компиляторы вырезают недостижимый код (smart linking): бинарники меньше в 1.5–5 раз.
Ключ `-nosmart` отключает оптимизацию. В `xdpw_2020` лежит прежний компилятор без неё.
Для KolibriOS реализованы модули:
* CRT
* LibImg
* LibINI
* Network
* OpenDlg
* ColorDlg
* TinyGL
[Сайт проекта XD Pascal для KolibriOS: xdpk](https://gitflic.ru/project/kolibrios-programming/xd-pascal)
[Архивная копия](https://web.archive.org/web/http://forum.cantor.systems/viewtopic.php?id=131) обсуждения на форуме.
+25
View File
@@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2009-2010, 2019-2020, Vasiliy Tereshkov
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,3 @@
..\xdpw_2026\xdpw source\XDPK.pas
move /y source\xdpk.exe xdpk.exe
pause
@@ -0,0 +1,6 @@
cd source
dcc32 xdpk.pas
copy xdpk.exe ..\xdpk.exe /y
del xdpk.exe, *.dcu
cd ..
pause
@@ -0,0 +1,24 @@
program ClrEolTest;
uses
CRT;
begin
CRT_initialization;
WriteLn('Hello, this is a ClrEolTest!');
Delay(500);
ClrScr;
Writeln('The function CLREOL clears all characters from the');
Delay(500);
Writeln('cursor position to the end of the line within the');
Delay(500);
Writeln('current text window, without moving the cursor.');
Delay(500);
Writeln('Press any key to continue . . .');
GotoXY(14, 4);
ReadKey;
ClrEOL;
ReadKey;
end.
@@ -0,0 +1,23 @@
{
launch this program with some
command line arguments
if argument has spaces then
need to quote them
for example:
CmdLineArgs.kex param1 param2 "p a r a m 3"
note that ParamStr(0) is always present
and contents full file path to CmdLineArgs.kex
}
{$APPTYPE CONSOLE}
program CmdLineArgs;
var
i: LongInt;
begin
WriteLn('ParamCount = ', ParamCount);
for i := 0 to ParamCount do
WriteLn('ParamStr(', i, ') = ', ParamStr(i));
end.
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,399 @@
// XD Pascal - a 32-bit compiler for KolibriOS
// Copyright (c) 2009-2010, 2019-2020, Vasiliy Tereshkov
{$I-}
{$H-}
unit Linker;
interface
uses Common, CodeGen;
procedure InitializeLinker;
procedure SetProgramEntryPoint;
function AddImportFunc(const ImportLibName, ImportFuncName: TString): LongInt;
procedure LinkAndWriteProgram(const ExeName: TString);
implementation
const
IMGBASE = $0;
SECTALIGN = $20;
FILEALIGN = SECTALIGN;
MAXIMPORTLIBS = 100;
MAXIMPORTS = 2000;
type
TDOSStub = array [0..127] of Byte;
TPEHeader = packed record
PE: array [0..3] of TCharacter;
Machine: Word;
NumberOfSections: Word;
TimeDateStamp: LongInt;
PointerToSymbolTable: LongInt;
NumberOfSymbols: LongInt;
SizeOfOptionalHeader: Word;
Characteristics: Word;
end;
TPEOptionalHeader = packed record
Magic: Word;
MajorLinkerVersion: Byte;
MinorLinkerVersion: Byte;
SizeOfCode: LongInt;
SizeOfInitializedData: LongInt;
SizeOfUninitializedData: LongInt;
AddressOfEntryPoint: LongInt;
BaseOfCode: LongInt;
BaseOfData: LongInt;
ImageBase: LongInt;
SectionAlignment: LongInt;
FileAlignment: LongInt;
MajorOperatingSystemVersion: Word;
MinorOperatingSystemVersion: Word;
MajorImageVersion: Word;
MinorImageVersion: Word;
MajorSubsystemVersion: Word;
MinorSubsystemVersion: Word;
Win32VersionValue: LongInt;
SizeOfImage: LongInt;
SizeOfHeaders: LongInt;
CheckSum: LongInt;
Subsystem: Word;
DllCharacteristics: Word;
SizeOfStackReserve: LongInt;
SizeOfStackCommit: LongInt;
SizeOfHeapReserve: LongInt;
SizeOfHeapCommit: LongInt;
LoaderFlags: LongInt;
NumberOfRvaAndSizes: LongInt;
end;
TDataDirectory = packed record
VirtualAddress: LongInt;
Size: LongInt;
end;
TPESectionHeader = packed record
Name: array [0..7] of TCharacter;
VirtualSize: LongInt;
VirtualAddress: LongInt;
SizeOfRawData: LongInt;
PointerToRawData: LongInt;
PointerToRelocations: LongInt;
PointerToLinenumbers: LongInt;
NumberOfRelocations: Word;
NumberOfLinenumbers: Word;
Characteristics: LongInt;
end;
THeaders = packed record
Signature: array [0..7] of TCharacter;
Version: LongInt;
EntryPoint: LongInt;
EndImage: LongInt;
Memory: LongInt;
StackTop: LongInt;
CmdLine: LongInt;
FilePath: LongInt;
end;
TImportLibName = array [0..15] of TCharacter;
TImportFuncName = array [0..31] of TCharacter;
TImportDirectoryTableEntry = packed record
Characteristics: LongInt;
TimeDateStamp: LongInt;
ForwarderChain: LongInt;
Name: LongInt;
FirstThunk: LongInt;
end;
TImportNameTableEntry = packed record
Hint: Word;
Name: TImportFuncName;
end;
TImport = record
LibName, FuncName: TString;
end;
TImportSectionData = record
DirectoryTable: array [1..MAXIMPORTLIBS + 1] of TImportDirectoryTableEntry;
LibraryNames: array [1..MAXIMPORTLIBS] of TImportLibName;
LookupTable: array [1..MAXIMPORTS + MAXIMPORTLIBS] of LongInt;
NameTable: array [1..MAXIMPORTS] of TImportNameTableEntry;
NumImports, NumImportLibs: Integer;
end;
var
Headers: THeaders;
Import: array [1..MAXIMPORTS] of TImport;
ImportSectionData: TImportSectionData;
LastImportLibName: TString;
ProgramEntryPoint: LongInt;
CodeSectionHeader_VirtualAddress: LongInt;
DataSectionHeader_VirtualAddress: LongInt;
BSSSectionHeader_VirtualAddress: LongInt;
ImportSectionHeader_VirtualAddress: LongInt;
{
const
DOSStub: TDOSStub =
(
$4D, $5A, $90, $00, $03, $00, $00, $00, $04, $00, $00, $00, $FF, $FF, $00, $00,
$B8, $00, $00, $00, $00, $00, $00, $00, $40, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $80, $00, $00, $00,
$0E, $1F, $BA, $0E, $00, $B4, $09, $CD, $21, $B8, $01, $4C, $CD, $21, $54, $68,
$69, $73, $20, $70, $72, $6F, $67, $72, $61, $6D, $20, $63, $61, $6E, $6E, $6F,
$74, $20, $62, $65, $20, $72, $75, $6E, $20, $69, $6E, $20, $44, $4F, $53, $20,
$6D, $6F, $64, $65, $2E, $0D, $0D, $0A, $24, $00, $00, $00, $00, $00, $00, $00
);
}
procedure Pad(var f: file; Size, Alignment: Integer);
var
i: Integer;
b: Byte;
begin
b := 0;
for i := 0 to Align(Size, Alignment) - Size - 1 do
BlockWrite(f, b, 1);
end;
procedure FillHeaders(CodeSize, InitializedDataSize, UninitializedDataSize, ImportSize: Integer);
const
PATH_SIZE = 1024;
PARAMS_SIZE = 256;
STACK_SIZE = 1024 * 1024;
begin
FillChar(Headers, SizeOf(Headers), #0);
CodeSectionHeader_VirtualAddress := Align(SizeOf(Headers), SECTALIGN);
DataSectionHeader_VirtualAddress := Align(SizeOf(Headers), SECTALIGN) + Align(CodeSize, SECTALIGN);
BSSSectionHeader_VirtualAddress := Align(SizeOf(Headers), SECTALIGN) + Align(CodeSize, SECTALIGN) + Align(InitializedDataSize, SECTALIGN);
ImportSectionHeader_VirtualAddress := Align(SizeOf(Headers), SECTALIGN) + Align(CodeSize, SECTALIGN) + Align(InitializedDataSize, SECTALIGN) + Align(UninitializedDataSize, SECTALIGN);
with Headers do
begin
Signature[0] := 'M';
Signature[1] := 'E';
Signature[2] := 'N';
Signature[3] := 'U';
Signature[4] := 'E';
Signature[5] := 'T';
Signature[6] := '0';
Signature[7] := '1';
Version := 1;
EntryPoint := Align(SizeOf(Headers), SECTALIGN) + ProgramEntryPoint;
EndImage := Align(SizeOf(Headers), SECTALIGN) + Align(CodeSize, SECTALIGN) + Align(InitializedDataSize, SECTALIGN);
FilePath := EndImage + Align(UninitializedDataSize, SECTALIGN);
Memory := FilePath + PATH_SIZE + PARAMS_SIZE + STACK_SIZE;
StackTop := FilePath + PATH_SIZE + PARAMS_SIZE + STACK_SIZE;
CmdLine := FilePath + PATH_SIZE;
end;
end;
procedure InitializeLinker;
begin
FillChar(Import, SizeOf(Import), #0);
FillChar(ImportSectionData, SizeOf(ImportSectionData), #0);
LastImportLibName := '';
ProgramEntryPoint := 0;
end;
procedure SetProgramEntryPoint;
begin
if ProgramEntryPoint <> 0 then
Error('Duplicate program entry point');
ProgramEntryPoint := GetCodeSize;
end;
function AddImportFunc(const ImportLibName, ImportFuncName: TString): LongInt;
begin
with ImportSectionData do
begin
Inc(NumImports);
if NumImports > MAXIMPORTS then
Error('Maximum number of import functions exceeded');
Import[NumImports].LibName := ImportLibName;
Import[NumImports].FuncName := ImportFuncName;
if ImportLibName <> LastImportLibName then
begin
Inc(NumImportLibs);
if NumImportLibs > MAXIMPORTLIBS then
Error('Maximum number of import libraries exceeded');
LastImportLibName := ImportLibName;
end;
Result := (NumImports - 1 + NumImportLibs - 1) * SizeOf(LongInt); // Relocatable
end;
end;
procedure FillImportSection(var ImportSize, LookupTableOffset: Integer);
var
ImportIndex, ImportLibIndex, LookupIndex: Integer;
LibraryNamesOffset, NameTableOffset: Integer;
begin
with ImportSectionData do
begin
LibraryNamesOffset := SizeOf(DirectoryTable[1]) * (NumImportLibs + 1);
LookupTableOffset := LibraryNamesOffset + SizeOf(LibraryNames[1]) * NumImportLibs;
NameTableOffset := LookupTableOffset + SizeOf(LookupTable[1]) * (NumImports + NumImportLibs);
ImportSize := NameTableOffset + SizeOf(NameTable[1]) * NumImports;
LastImportLibName := '';
ImportLibIndex := 0;
LookupIndex := 0;
for ImportIndex := 1 to NumImports do
begin
// Add new import library
if (ImportLibIndex = 0) or (Import[ImportIndex].LibName <> LastImportLibName) then
begin
if ImportLibIndex <> 0 then Inc(LookupIndex); // Add null entry before the first thunk of a new library
Inc(ImportLibIndex);
DirectoryTable[ImportLibIndex].Name := LibraryNamesOffset + SizeOf(LibraryNames[1]) * (ImportLibIndex - 1);
DirectoryTable[ImportLibIndex].FirstThunk := LookupTableOffset + SizeOf(LookupTable[1]) * LookupIndex;
Move(Import[ImportIndex].LibName[1], LibraryNames[ImportLibIndex], Length(Import[ImportIndex].LibName));
LastImportLibName := Import[ImportIndex].LibName;
end; // if
// Add new import function
Inc(LookupIndex);
if LookupIndex > MAXIMPORTS + MAXIMPORTLIBS then
Error('Maximum number of lookup entries exceeded');
LookupTable[LookupIndex] := NameTableOffset + SizeOf(NameTable[1]) * (ImportIndex - 1);
Move(Import[ImportIndex].FuncName[1], NameTable[ImportIndex].Name, Length(Import[ImportIndex].FuncName));
end;
end;
end;
procedure FixupImportSection(VirtualAddress: LongInt);
var
i: Integer;
begin
with ImportSectionData do
begin
for i := 1 to NumImportLibs do
with DirectoryTable[i] do
begin
Name := Name + VirtualAddress;
FirstThunk := FirstThunk + VirtualAddress;
end;
for i := 1 to NumImports + NumImportLibs do
if LookupTable[i] <> 0 then
LookupTable[i] := LookupTable[i] + VirtualAddress;
end;
end;
procedure LinkAndWriteProgram(const ExeName: TString);
var
OutFile: TOutFile;
CodeSize, ImportSize, LookupTableOffset: Integer;
begin
if ProgramEntryPoint = 0 then
Error('Program entry point not found');
CodeSize := GetCodeSize;
FillImportSection(ImportSize, LookupTableOffset);
FillHeaders(CodeSize, InitializedGlobalDataSize, UninitializedGlobalDataSize, ImportSize);
Relocate(IMGBASE + CodeSectionHeader_VirtualAddress,
IMGBASE + DataSectionHeader_VirtualAddress,
IMGBASE + BSSSectionHeader_VirtualAddress,
IMGBASE + ImportSectionHeader_VirtualAddress + LookupTableOffset);
//FixupImportSection(Headers.ImportSectionHeader.VirtualAddress);
// Write output file
Assign(OutFile, TGenericString(ExeName));
Rewrite(OutFile, 1);
if IOResult <> 0 then
Error('Unable to open output file ' + ExeName);
BlockWrite(OutFile, Headers, SizeOf(Headers));
Pad(OutFile, SizeOf(Headers), FILEALIGN);
BlockWrite(OutFile, Code, CodeSize);
Pad(OutFile, CodeSize, FILEALIGN);
BlockWrite(OutFile, InitializedGlobalData, InitializedGlobalDataSize);
Pad(OutFile, InitializedGlobalDataSize, FILEALIGN);
{
with ImportSectionData do
begin
BlockWrite(OutFile, DirectoryTable, SizeOf(DirectoryTable[1]) * (NumImportLibs + 1));
BlockWrite(OutFile, LibraryNames, SizeOf(LibraryNames[1]) * NumImportLibs);
BlockWrite(OutFile, LookupTable, SizeOf(LookupTable[1]) * (NumImports + NumImportLibs));
BlockWrite(OutFile, NameTable, SizeOf(NameTable[1]) * NumImports);
end;
Pad(OutFile, ImportSize, FILEALIGN);
}
Close(OutFile);
end;
end.
@@ -0,0 +1,4 @@
#SHS
rm xdpk.kex
../../xdpk.kex xdpk.pas
exit
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,698 @@
// XD Pascal - a 32-bit compiler for KolibriOS
// Copyright (c) 2009-2010, 2019-2020, Vasiliy Tereshkov
{$I-}
{$H-}
unit Scanner;
interface
uses Common;
var
Tok: TToken;
procedure InitializeScanner(const Name: TString);
function SaveScanner: Boolean;
function RestoreScanner: Boolean;
procedure FinalizeScanner;
procedure NextTok;
procedure CheckTok(ExpectedTokKind: TTokenKind);
procedure EatTok(ExpectedTokKind: TTokenKind);
procedure AssertIdent;
function ScannerFileName: TString;
function ScannerLine: Integer;
implementation
type
TBuffer = record
Ptr: PCharacter;
Size, Pos: Integer;
end;
TScannerState = record
Token: TToken;
FileName: TString;
Line: Integer;
Buffer: TBuffer;
ch, ch2: TCharacter;
EndOfUnit: Boolean;
end;
const
SCANNERSTACKSIZE = 10;
var
ScannerState: TScannerState;
ScannerStack: array [1..SCANNERSTACKSIZE] of TScannerState;
ScannerStackTop: Integer = 0;
const
Digits: set of TCharacter = ['0'..'9'];
HexDigits: set of TCharacter = ['0'..'9', 'A'..'F'];
Spaces: set of TCharacter = [#1..#31, ' '];
AlphaNums: set of TCharacter = ['A'..'Z', 'a'..'z', '0'..'9', '_'];
procedure InitializeScanner(const Name: TString);
var
F: TInFile;
ActualSize: Integer;
FolderIndex: Integer;
begin
ScannerState.Buffer.Ptr := nil;
// First search the source folder, then the units folder, then the folders specified in $UNITPATH
FolderIndex := 1;
repeat
Assign(F, TGenericString(Folders[FolderIndex] + Name));
Reset(F, 1);
if IOResult = 0 then Break;
Inc(FolderIndex);
until FolderIndex > NumFolders;
if FolderIndex > NumFolders then
Error('Unable to open source file ' + Name);
with ScannerState do
begin
FileName := Name;
Line := 1;
with Buffer do
begin
Size := FileSize(F);
Pos := 0;
GetMem(Ptr, Size);
ActualSize := 0;
BlockRead(F, Ptr^, Size, ActualSize);
Close(F);
if ActualSize <> Size then
Error('Unable to read source file ' + Name);
end;
ch := ' ';
ch2 := ' ';
EndOfUnit := FALSE;
end;
end;
function SaveScanner: Boolean;
begin
Result := FALSE;
if ScannerStackTop < SCANNERSTACKSIZE then
begin
Inc(ScannerStackTop);
ScannerStack[ScannerStackTop] := ScannerState;
Result := TRUE;
end;
end;
function RestoreScanner: Boolean;
begin
Result := FALSE;
if ScannerStackTop > 0 then
begin
ScannerState := ScannerStack[ScannerStackTop];
Dec(ScannerStackTop);
Tok := ScannerState.Token;
Result := TRUE;
end;
end;
procedure FinalizeScanner;
begin
ScannerState.EndOfUnit := TRUE;
with ScannerState.Buffer do
if Ptr <> nil then
begin
FreeMem(Ptr);
Ptr := nil;
end;
end;
procedure AppendStrSafe(var s: TString; ch: TCharacter);
begin
if Length(s) >= MAXSTRLENGTH - 1 then
Error('String is too long');
s := s + ch;
end;
procedure ReadChar(var ch: TCharacter);
begin
if ScannerState.ch = #10 then Inc(ScannerState.Line); // End of line found
ch := #0;
with ScannerState.Buffer do
if Pos < Size then
begin
ch := PCharacter(Integer(Ptr) + Pos)^;
Inc(Pos);
end
else
ScannerState.EndOfUnit := TRUE;
end;
procedure ReadUppercaseChar(var ch: TCharacter);
begin
ReadChar(ch);
ch := UpCase(ch);
end;
procedure ReadLiteralChar(var ch: TCharacter);
begin
ReadChar(ch);
if (ch = #0) or (ch = #10) then
Error('Unterminated string');
end;
procedure ReadSingleLineComment;
begin
with ScannerState do
while (ch <> #10) and not EndOfUnit do
ReadChar(ch);
end;
procedure ReadMultiLineComment;
begin
with ScannerState do
while (ch <> '}') and not EndOfUnit do
ReadChar(ch);
end;
procedure ReadDirective;
var
Text: TString;
begin
with ScannerState do
begin
Text := '';
repeat
AppendStrSafe(Text, ch);
ReadUppercaseChar(ch);
until not (ch in AlphaNums);
if Text = '$APPTYPE' then // Console/GUI application type directive
begin
Text := '';
ReadChar(ch);
while (ch <> '}') and not EndOfUnit do
begin
if (ch = #0) or (ch > ' ') then
AppendStrSafe(Text, UpCase(ch));
ReadChar(ch);
end;
if Text = 'CONSOLE' then
IsConsoleProgram := TRUE
else if Text = 'GUI' then
IsConsoleProgram := FALSE
else
Error('Unknown application type ' + Text);
end
else if Text = '$UNITPATH' then // Unit path directive
begin
Text := '';
ReadChar(ch);
while (ch <> '}') and not EndOfUnit do
begin
if (ch = #0) or (ch > ' ') then
AppendStrSafe(Text, UpCase(ch));
ReadChar(ch);
end;
Inc(NumFolders);
if NumFolders > MAXFOLDERS then
Error('Maximum number of unit paths exceeded');
Folders[NumFolders] := Folders[1] + Text;
end
else // All other directives are ignored
ReadMultiLineComment;
end;
end;
procedure ReadHexadecimalNumber;
var
Num, Digit: Integer;
NumFound: Boolean;
begin
with ScannerState do
begin
Num := 0;
NumFound := FALSE;
while ch in HexDigits do
begin
if Num and $F0000000 <> 0 then
Error('Numeric constant is too large');
if ch in Digits then
Digit := Ord(ch) - Ord('0')
else
Digit := Ord(ch) - Ord('A') + 10;
Num := Num shl 4 or Digit;
NumFound := TRUE;
ReadUppercaseChar(ch);
end;
if not NumFound then
Error('Hexadecimal constant is not found');
Token.Kind := INTNUMBERTOK;
Token.OrdValue := Num;
end;
end;
procedure ReadDecimalNumber;
var
Num, Expon, Digit: Integer;
Frac, FracWeight: Double;
NegExpon, RangeFound, ExponFound: Boolean;
begin
with ScannerState do
begin
Num := 0;
Frac := 0;
Expon := 0;
NegExpon := FALSE;
while ch in Digits do
begin
Digit := Ord(ch) - Ord('0');
if Num > (HighBound(INTEGERTYPEINDEX) - Digit) div 10 then
Error('Numeric constant is too large');
Num := 10 * Num + Digit;
ReadUppercaseChar(ch);
end;
if (ch <> '.') and (ch <> 'E') then // Integer number
begin
Token.Kind := INTNUMBERTOK;
Token.OrdValue := Num;
end
else
begin
// Check for '..' token
RangeFound := FALSE;
if ch = '.' then
begin
ReadUppercaseChar(ch2);
if ch2 = '.' then // Integer number followed by '..' token
begin
Token.Kind := INTNUMBERTOK;
Token.OrdValue := Num;
RangeFound := TRUE;
end;
if not EndOfUnit then Dec(Buffer.Pos);
end; // if ch = '.'
if not RangeFound then // Fractional number
begin
// Check for fractional part
if ch = '.' then
begin
FracWeight := 0.1;
ReadUppercaseChar(ch);
while ch in Digits do
begin
Digit := Ord(ch) - Ord('0');
Frac := Frac + FracWeight * Digit;
FracWeight := FracWeight / 10;
ReadUppercaseChar(ch);
end;
end; // if ch = '.'
// Check for exponent
if ch = 'E' then
begin
ReadUppercaseChar(ch);
// Check for exponent sign
if ch = '+' then
ReadUppercaseChar(ch)
else if ch = '-' then
begin
NegExpon := TRUE;
ReadUppercaseChar(ch);
end;
ExponFound := FALSE;
while ch in Digits do
begin
Digit := Ord(ch) - Ord('0');
Expon := 10 * Expon + Digit;
ReadUppercaseChar(ch);
ExponFound := TRUE;
end;
if not ExponFound then
Error('Exponent is not found');
if NegExpon then Expon := -Expon;
end; // if ch = 'E'
Token.Kind := REALNUMBERTOK;
Token.RealValue := (Num + Frac) * exp(Expon * ln(10));
end; // if not RangeFound
end; // else
end;
end;
procedure ReadNumber;
begin
with ScannerState do
if ch = '$' then
begin
ReadUppercaseChar(ch);
ReadHexadecimalNumber;
end
else
ReadDecimalNumber;
end;
procedure ReadCharCode;
begin
with ScannerState do
begin
ReadUppercaseChar(ch);
if not (ch in Digits + ['$']) then
Error('Character code is not found');
ReadNumber;
if (Token.Kind = REALNUMBERTOK) or (Token.OrdValue < 0) or (Token.OrdValue > 255) then
Error('Illegal character code');
Token.Kind := CHARLITERALTOK;
end;
end;
procedure ReadKeywordOrIdentifier;
var
Text, NonUppercaseText: TString;
CurToken: TTokenKind;
begin
with ScannerState do
begin
Text := '';
NonUppercaseText := '';
repeat
AppendStrSafe(NonUppercaseText, ch);
ch := UpCase(ch);
AppendStrSafe(Text, ch);
ReadChar(ch);
until not (ch in AlphaNums);
CurToken := GetKeyword(Text);
if CurToken <> EMPTYTOK then // Keyword found
Token.Kind := CurToken
else
begin // Identifier found
Token.Kind := IDENTTOK;
Token.Name := Text;
Token.NonUppercaseName := NonUppercaseText;
end;
end;
end;
procedure ReadCharOrStringLiteral;
var
Text: TString;
EndOfLiteral: Boolean;
begin
with ScannerState do
begin
Text := '';
EndOfLiteral := FALSE;
repeat
ReadLiteralChar(ch);
if ch <> '''' then
AppendStrSafe(Text, ch)
else
begin
ReadChar(ch2);
if ch2 = '''' then // Apostrophe character found
AppendStrSafe(Text, ch)
else
begin
if not EndOfUnit then Dec(Buffer.Pos); // Discard ch2
EndOfLiteral := TRUE;
end;
end;
until EndOfLiteral;
if Length(Text) = 1 then
begin
Token.Kind := CHARLITERALTOK;
Token.OrdValue := Ord(Text[1]);
end
else
begin
Token.Kind := STRINGLITERALTOK;
Token.Name := Text;
Token.StrLength := Length(Text);
DefineStaticString(Text, Token.StrAddress);
end;
ReadUppercaseChar(ch);
end;
end;
procedure NextTok;
begin
with ScannerState do
begin
Token.Kind := EMPTYTOK;
// Skip spaces, comments, directives
while (ch in Spaces) or (ch = '{') or (ch = '/') do
begin
if ch = '{' then // Multi-line comment or directive
begin
ReadUppercaseChar(ch);
if ch = '$' then ReadDirective else ReadMultiLineComment;
end
else if ch = '/' then
begin
ReadUppercaseChar(ch2);
if ch2 = '/' then
ReadSingleLineComment // Double-line comment
else
begin
if not EndOfUnit then Dec(Buffer.Pos); // Discard ch2
Break;
end;
end;
ReadChar(ch);
end;
// Read token
case ch of
'0'..'9', '$':
ReadNumber;
'#':
ReadCharCode;
'A'..'Z', 'a'..'z', '_':
ReadKeywordOrIdentifier;
'''':
ReadCharOrStringLiteral;
':': // Single- or double-character tokens
begin
Token.Kind := COLONTOK;
ReadUppercaseChar(ch);
if ch = '=' then
begin
Token.Kind := ASSIGNTOK;
ReadUppercaseChar(ch);
end;
end;
'>':
begin
Token.Kind := GTTOK;
ReadUppercaseChar(ch);
if ch = '=' then
begin
Token.Kind := GETOK;
ReadUppercaseChar(ch);
end;
end;
'<':
begin
Token.Kind := LTTOK;
ReadUppercaseChar(ch);
if ch = '=' then
begin
Token.Kind := LETOK;
ReadUppercaseChar(ch);
end
else if ch = '>' then
begin
Token.Kind := NETOK;
ReadUppercaseChar(ch);
end;
end;
'.':
begin
Token.Kind := PERIODTOK;
ReadUppercaseChar(ch);
if ch = '.' then
begin
Token.Kind := RANGETOK;
ReadUppercaseChar(ch);
end;
end
else // Double-character tokens
case ch of
'=': Token.Kind := EQTOK;
',': Token.Kind := COMMATOK;
';': Token.Kind := SEMICOLONTOK;
'(': Token.Kind := OPARTOK;
')': Token.Kind := CPARTOK;
'*': Token.Kind := MULTOK;
'/': Token.Kind := DIVTOK;
'+': Token.Kind := PLUSTOK;
'-': Token.Kind := MINUSTOK;
'^': Token.Kind := DEREFERENCETOK;
'@': Token.Kind := ADDRESSTOK;
'[': Token.Kind := OBRACKETTOK;
']': Token.Kind := CBRACKETTOK
else
Error('Unexpected character or end of file');
end; // case
ReadChar(ch);
end; // case
end;
Tok := ScannerState.Token;
end; // NextTok
procedure CheckTok(ExpectedTokKind: TTokenKind);
begin
with ScannerState do
if Token.Kind <> ExpectedTokKind then
Error(GetTokSpelling(ExpectedTokKind) + ' expected but ' + GetTokSpelling(Token.Kind) + ' found');
end;
procedure EatTok(ExpectedTokKind: TTokenKind);
begin
CheckTok(ExpectedTokKind);
NextTok;
end;
procedure AssertIdent;
begin
with ScannerState do
if Token.Kind <> IDENTTOK then
Error('Identifier expected but ' + GetTokSpelling(Token.Kind) + ' found');
end;
function ScannerFileName: TString;
begin
Result := ScannerState.FileName;
end;
function ScannerLine: Integer;
begin
Result := ScannerState.Line;
end;
end.
@@ -0,0 +1,128 @@
// XD Pascal - a 32-bit compiler for KolibriOS
// Copyright (c) 2009-2010, 2019-2020, Vasiliy Tereshkov
{$APPTYPE CONSOLE}
{$I-}
{$H-}
program XDPK;
uses SysUtils, Common, Scanner, Parser, CodeGen, Linker;
procedure SplitPath(const Path: TString; var Folder, Name, Ext: TString);
var
DotPos, SlashPos, i: Integer;
begin
Folder := '';
Name := Path;
Ext := '';
DotPos := 0;
SlashPos := 0;
for i := Length(Path) downto 1 do
if (Path[i] = '.') and (DotPos = 0) then
DotPos := i
else if (Path[i] = '/') and (SlashPos = 0) then
SlashPos := i;
if DotPos > 0 then
begin
Name := Copy(Path, 1, DotPos - 1);
Ext := Copy(Path, DotPos, Length(Path) - DotPos + 1);
end;
if SlashPos > 0 then
begin
Folder := Copy(Path, 1, SlashPos);
Name := Copy(Path, SlashPos + 1, Length(Name) - SlashPos);
end;
end;
procedure NoticeProc(ClassInstance: Pointer; const Msg: TString);
begin
WriteLn(Msg);
end;
procedure WarningProc(ClassInstance: Pointer; const Msg: TString);
begin
if NumUnits >= 1 then
Notice(ScannerFileName + ' (' + IntToStr(ScannerLine) + ') Warning: ' + Msg)
else
Notice('Warning: ' + Msg);
end;
procedure ErrorProc(ClassInstance: Pointer; const Msg: TString);
begin
if NumUnits >= 1 then
Notice(ScannerFileName + ' (' + IntToStr(ScannerLine) + ') Error: ' + Msg)
else
Notice('Error: ' + Msg);
repeat FinalizeScanner until not RestoreScanner;
FinalizeCommon;
Halt(1);
end;
var
CompilerPath, CompilerFolder, CompilerName, CompilerExt,
PasPath, PasFolder, PasName, PasExt,
ExePath: TString;
begin
SetWriteProcs(nil, @NoticeProc, @WarningProc, @ErrorProc);
Notice('XD Pascal for KolibriOS ' + VERSION);
Notice('Copyright (c) 2009-2010, 2019-2020, Vasiliy Tereshkov');
if ParamCount < 1 then
begin
Notice('Usage: xdpk <file.pas>');
Halt(1);
end;
CompilerPath := TString(ParamStr(0));
SplitPath(CompilerPath, CompilerFolder, CompilerName, CompilerExt);
PasPath := TString(ParamStr(1));
SplitPath(PasPath, PasFolder, PasName, PasExt);
InitializeCommon;
InitializeLinker;
InitializeCodeGen;
Folders[1] := PasFolder;
Folders[2] := CompilerFolder + 'units/';
NumFolders := 2;
CompileProgramOrUnit('system.pas');
CompileProgramOrUnit(PasName + PasExt);
ExePath := PasFolder + PasName + '.kex';
LinkAndWriteProgram(ExePath);
Notice('Complete. Code size: ' + IntToStr(GetCodeSize) + ' bytes. Data size: ' + IntToStr(InitializedGlobalDataSize + UninitializedGlobalDataSize) + ' bytes');
repeat FinalizeScanner until not RestoreScanner;
FinalizeCommon;
end.
@@ -0,0 +1,5 @@
if exist xdpk.kex del xdpk.kex
..\..\xdpk xdpk.pas
if exist xdpk.kex ..\..\kpack xdpk.kex
pause
@@ -0,0 +1,87 @@
program Draw_Scaled_PNG_Image;
uses
KolibriOS, LibImg;
var
WndLeft, WndTop, WndWidth, WndHeight: Integer;
ImageToDraw: PImage; // шчюсЁрцхэшх, ъюЄюЁюх сєфхь ЁшёютрЄ№
// яЁюсєхь чруЁєчшЄ№ Їрщы шчюсЁрцхэш , фхъюфшЁютрЄ№ ш ьрё°ЄрсшЁютрЄ№
function OpenImageFile(FilePath: PAnsiChar): PImage;
var
FileAttributes: TFileAttributes;
BytesRead: Integer;
imgFile: Pointer;
imgFileSize: Integer;
imgData, imgScaled: PImage;
begin
Result := nil;
// хёыш Їрщы фюёЄєяхэ
if GetFileAttributes(FilePath, FileAttributes) = 0 then
begin
// єчэр╕ь ЁрчьхЁ Їрщыр т срщЄрї
imgFileSize := FileAttributes.SizeLo;
// т√фхы хь ярь Є№ фы  ўЄхэш  Єєфр ¤Єюую Їрщыр
GetMem(imgFile, imgFileSize);
// ўшЄрхь Їрщы
ReadFile(FilePath, PAnsiChar(imgFile)^, imgFileSize, 0, 0, BytesRead);
// яЁюсєхь фхъюфшЁютрЄ№ Їрщы шчюсЁрцхэш 
imgData := img_decode(imgFile, imgFileSize, nil);
// юётюсюцфрхь т√фхыхээє■ яюф Їрщы ярь Є№
FreeMem(imgFile);
// хёыш єфрыюё№ фхъюфшЁютрЄ№ Їрщы шчюсЁрцхэш 
if imgData <> nil then
begin
// хёыш эхяюффхЁцштрхьр  сшсышюЄхъющ уыєсшэр ЎтхЄр
if not (imgData^.ImageType in [IMAGE_BPP24, IMAGE_BPP32, IMAGE_BPP8G]) then
begin
// ъюэтхЁЄшЁєхь т шчюсЁрцхэшх ё яюффхЁцштрхьющ уыєсшэющ
imgScaled := img_convert(imgData, nil, IMAGE_BPP24, 0, 0);
// єэшўЄюцрхь шёїюфэюх шчюсЁрцхэшх
img_destroy(imgData);
imgData := imgScaled;
end;
// яЁюсєхь ьрё°ЄрсшЁютрЄ№ т эют√щ ЁрчьхЁ 200x150
imgScaled := img_scale(imgData, 0, 0, imgData^.Width, imgData^.Height,
nil, LIBIMG_SCALE_STRETCH, LIBIMG_INTER_DEFAULT, 200, 150);
Result := imgScaled;
end;
end;
end;
begin
//SetAppDirAsCurrent;
LibImg_initialization;
with GetScreenSize do
begin
WndWidth := Width div 4;
WndHeight := Height div 4;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
ImageToDraw := OpenImageFile('./Background.png');
while True do
case WaitEvent of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'Draw Scaled PNG Image', $00FFFFFF,
WS_SKINNED_FIXED + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
// хёыш яюыєўшыюё№ ьрё°ЄрсшЁютрЄ№, Єю Ёшёєхь хую т Єюўъх (10, 5)
if ImageToDraw <> nil then
img_draw(ImageToDraw, 10, 5, $ffffffff, $ffffffff, 0, 0);
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
Exit;
end;
end.
@@ -0,0 +1,12 @@
{$APPTYPE CONSOLE}
program EnterNumber;
var
Number: LongInt;
begin
Write('Enter Number please:');
ReadLn(Number);
WriteLn('You entered "', Number, '"');
end.
@@ -0,0 +1,48 @@
program ExpSinGraph_CRT;
{ example from K. Jensen, N. Wirth "Pascal User Manual and Report" }
uses
CRT;
const
d = 1 / 16; // 16 lines for interval [x, x + 1]
s = 32 / 1.5; // 32 character widths for interval [y, y + 1]
h = 34; // character position of x-axis
c = 2 * PI;
lim = 32;
var
i, n: Integer;
x, y: Extended;
Colors: array [0..14] of Byte = (LightRed, Yellow, LightGreen, LightCyan, LightBlue,
LightMagenta, White, LightGray, DarkGray, Magenta, Blue, Cyan, Green, Brown, Red);
ColorIndex: Integer = 0;
procedure SwitchColor;
begin
TextColor(Colors[ColorIndex]);
Inc(ColorIndex);
if ColorIndex > High(Colors) then
ColorIndex := Low(Colors);
end;
begin
CRT_initialization();
for i := 0 to lim do
begin
x := d * i;
y := Exp(-x) * Sin(c * x);
n := Round(s * y) + h;
SwitchColor();
repeat
Write(' ');
Dec(n);
until n = 0;
WriteLn('*');
end;
end.
@@ -0,0 +1,24 @@
program GetIPAddr;
uses
KolibriOS, Network;
var
AddrInfo: PAddrInfo;
InputStr: string;
begin
Network_initialization;
while True do
begin
Write('Input host:'); ReadLn(InputStr);
if getaddrinfo(InputStr, nil, nil, AddrInfo) = 0{success} then
WriteLn(PString(inet_ntoa(AddrInfo^.ai_addr^.sin_addr))^)
else
WriteLn('Error!');
freeaddrinfo(AddrInfo);
Write('Continue?[Y/N]:'); ReadLn(InputStr);
if UpCase(InputStr[1]) = 'N' then Exit;
end;
end.
@@ -0,0 +1,49 @@
program INI_File_Read;
uses
LibINI;
procedure IniKeyCallback(FileName, SectionName, KeyName, KeyValue: PAnsiChar) stdcall;
begin
Write(' ', PString(KeyName)^);
Write(' = ');
WriteLn(PString(KeyValue)^);
end;
procedure IniSectionCallback(FileName, SectionName: PAnsiChar) stdcall;
begin
WriteLn(PString(SectionName)^);
ini_enum_keys(FileName, SectionName, @IniKeyCallback);
end;
const
FILE_PATH = '/sys/settings/system.ini';
var
SystemLang: array [0..255] of AnsiChar;
MouseSpeed: Integer;
begin
LibINI_initialization;
WriteLn('Hello, this is a test for LibINI!');
WriteLn;
ini_enum_sections(FILE_PATH, @IniSectionCallback);
WriteLn;
WriteLn('Try to get system.language and mouse.speed:');
if ini_get_str(FILE_PATH, 'system', 'language', SystemLang, SizeOf(SystemLang), 'ru') = 0 then
WriteLn('Lang = "', SystemLang, '"')
else
WriteLn('Lang not found, used default "', SystemLang , '"');
MouseSpeed := ini_get_int(FILE_PATH, 'mouse', 'speed', -1);
if MouseSpeed <> -1 then
WriteLn('MouseSpeed = "', MouseSpeed, '"')
else
begin
MouseSpeed := 5;
WriteLn('MouseSpeed not found, used default "', MouseSpeed , '"');
end;
end.
@@ -0,0 +1,22 @@
program Just_Window;
uses
KolibriOS;
begin
while True do
case WaitEvent of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(300, 200, 350, 250, 'Hello from XDPascal!', $00D5E3F1,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
Exit;
end;
end.
@@ -0,0 +1,38 @@
#SHS
rm ClrEOL_CRT.kex
rm CmdLineArgs.kex
rm Draw_Scaled_PNG_Image.kex
rm EnterNumber.kex
rm ExpSinGraph_CRT.kex
rm factor.kex
rm GetIPAddr.kex
rm hello.kex
rm INI_file_Read.kex
rm Just_Window.kex
rm Mouse_Test.kex
rm Pyramid_TinyGL.kex
rm raytracer.kex
rm Select_Color_in_ColorDialog.kex
rm Select_File_in_OpenDialog.kex
rm Sierpinski.kex
rm sort.kex
rm SpiralMat.kex
../xdpk.kex ClrEOL_CRT.pas
../xdpk.kex CmdLineArgs.pas
../xdpk.kex Draw_Scaled_PNG_Image.pas
../xdpk.kex EnterNumber.pas
../xdpk.kex ExpSinGraph_CRT.pas
../xdpk.kex factor.pas
../xdpk.kex GetIPAddr.pas
../xdpk.kex hello.pas
../xdpk.kex INI_file_Read.pas
../xdpk.kex Just_Window.pas
../xdpk.kex Mouse_Test.pas
../xdpk.kex Pyramid_TinyGL.pas
../xdpk.kex raytracer.pas
../xdpk.kex Select_Color_in_ColorDialog.pas
../xdpk.kex Select_File_in_OpenDialog.pas
../xdpk.kex Sierpinski.pas
../xdpk.kex sort.pas
../xdpk.kex SpiralMat.pas
exit
@@ -0,0 +1,74 @@
program Mouse_Test;
uses
KolibriOS;
const
MY_BUTTON = 1000;
var
WndLeft, WndTop, WndWidth, WndHeight: Integer;
TxtClickResult: string = 'Yet not clicked.';
procedure On_Redraw;
begin
BeginDraw;
DrawWindow(300, 200, 350, 250, 'Mouse test.', $00D5E3F1,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
DrawButton(10, 20, 50, 30, $0075D3F1, 0, MY_BUTTON);
DrawText(20, 55, 'Click on window', $00AF4F3F, 0,
DT_CP866_8X16 + DT_TRANSPARENT_FILL + DT_ZSTRING, 0);
DrawText(20, 70, 'or click on button', $003F4FAF, 0,
DT_CP866_8X16 + DT_TRANSPARENT_FILL + DT_ZSTRING, 0);
DrawText(15, 90, TxtClickResult, $001F7F1F, 0,
DT_CP866_8X16 + DT_TRANSPARENT_FILL, Length(TxtClickResult));
EndDraw;
end;
begin
with GetScreenSize do
begin
WndWidth := Width div 2;
WndHeight := Height div 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
SetEventMask(EM_REDRAW + EM_BUTTON + EM_KEY + EM_MOUSE);
while True do
case WaitEvent of
REDRAW_EVENT:
On_Redraw;
KEY_EVENT:
GetKey;
MOUSE_EVENT:
begin
case GetMouseButtons of
1: if GetWindowMousePos.X > 100 then
TxtClickResult := 'Left mouse button down(X > 100).'
else
TxtClickResult := 'Left mouse button down(X <= 100).';
2: TxtClickResult := 'Right mouse button down.';
4: TxtClickResult := 'Middle mouse button down.';
end;
On_Redraw;
end;
BUTTON_EVENT:
with GetButton do
case ID of
1: Exit;
MY_BUTTON:
begin
case MouseButton of
0: TxtClickResult := 'Button clicked by left mouse button.';
2: TxtClickResult := 'Button clicked by right mouse button.';
4: TxtClickResult := 'Button clicked by middle mouse button.';
end;
On_Redraw;
end;
end;
end;
end.
@@ -0,0 +1,104 @@
program Pyramid_TinyGL;
uses
KolibriOS, TinyGL;
var
CTX: TKOSGLContext;
Angle: GLFloat = 0;
Speed: GLFloat = 3.5;
WndLeft, WndTop, WndWidth, WndHeight: Integer;
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
if ThreadInfo.Client.Height <= 3 then Exit; // otherwise app crashes
kosglMakeCurrent(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height, CTX);
glViewPort (0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glClearColor(0.11, 0.22, 0.66, 0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(45.0, ThreadInfo.Client.Width / ThreadInfo.Client.Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -5);
glRotatef(Angle, 0.25, 0.75, 0.75);
glBegin(GL_TRIANGLE_FAN);
glColor3f(1, 0, 0); glVertex3f(0, 0.75, 0);
glColor3f(1, 1, 0); glVertex3f(-0.75, -0.75, 0.75);
glColor3f(1, 1, 1); glVertex3f(0.75, -0.75, 0.75);
glColor3f(0, 1, 1); glVertex3f(0.75, -0.75, -0.75);
glColor3f(0, 0, 1); glVertex3f(-0.75, -0.75, -0.75);
glColor3f(0, 1, 0); glVertex3f(-0.75, -0.75, 0.75);
glEnd();
Angle := Angle + Speed;
if Angle > 360 then Angle := 0;
kosglSwapBuffers();
end;
begin
TinyGL_initialization;
with GetScreenSize do
begin
WndWidth := Width div 2;
WndHeight := Height div 3 * 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'Pyramid TinyGL', $00FFFFFF,
WS_SKINNED_SIZABLE + WS_TRANSPARENT_FILL + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
GLDraw;
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
Exit;
else
GLDraw;
end;
end.
@@ -0,0 +1,61 @@
program Select_Color_in_ColorDialog;
uses
KolibriOS, ColorDlg;
var
WndLeft, WndTop, WndWidth, WndHeight: Integer;
TextColor: Integer = $00707070;
ColorDialog: TColorDialog;
procedure On_Redraw;
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'Test ColorDialog, press key to select text color', $00FAFBFC,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
DrawText(2, 75, 'press key to select text color', TextColor, 0,
DT_CP866_8X16 + DT_TRANSPARENT_FILL + DT_ZSTRING + DT_X2, 0);
EndDraw;
end;
begin
ColorDlg_initialization;
with ColorDialog do
begin
Mode := CDM_PALETTE_TONE;
DrawWindow := @On_Redraw;
XSize := 510;
YSize := 310;
ColorType := CDCT_RGB;
end;
with GetScreenSize do
begin
WndWidth := 600;
WndHeight := Height div 3;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
ColorDialog.Init();
while True do
case WaitEvent of
REDRAW_EVENT:
On_Redraw;
KEY_EVENT:
begin
GetKey;
ColorDialog.Start();
with ColorDialog do
if Status = CDS_OK then
begin
TextColor := Color;
On_Redraw;
end;
end;
BUTTON_EVENT:
Exit;
end;
end.
@@ -0,0 +1,90 @@
program Select_File_in_OpenDialog;
uses
KolibriOS, OpenDlg;
var
WndLeft, WndTop, WndWidth, WndHeight: Integer;
OpenDialog: TOpenDialog;
TxtSelectResult: string = 'Yet not selected.';
procedure On_Redraw;
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'Select File in OpenDialog', $00FFFFFF,
WS_SKINNED_FIXED + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
DrawText(2, 75, 'press key ENTER to select file', $00AF4F3F, 0,
DT_CP866_8X16 + DT_TRANSPARENT_FILL + DT_ZSTRING, 0);
DrawText(2, 90, 'press key SPACE to select dir', $003F4FAF, 0,
DT_CP866_8X16 + DT_TRANSPARENT_FILL + DT_ZSTRING, 0);
DrawText(15, 110, TxtSelectResult, $001F7F1F, 0,
DT_CP866_8X16 + DT_TRANSPARENT_FILL, Length(TxtSelectResult));
EndDraw;
end;
procedure BrowseFile;
begin
with OpenDialog do
begin
Mode := ODM_OPEN;
Start();
if Status = ODS_OK then
begin
TxtSelectResult := 'File = "' + PString(OpenFilePath)^ + '"';
On_Redraw;
end;
end;
end;
procedure BrowseDir;
begin
with OpenDialog do
begin
Mode := ODM_DIR;
Start();
if Status = ODS_OK then
begin
TxtSelectResult := 'Dir = "' + PString(OpenFilePath)^ + '"';
On_Redraw;
end;
end;
end;
begin
OpenDlg_initialization;
with OpenDialog do
begin
DirDefaultPath := '/sys';
DrawWindow := @On_Redraw;
XSize := 400;
YSize := 480;
end;
with GetScreenSize do
begin
WndWidth := Width div 4;
WndHeight := Height div 4;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
OpenDialog.Init();
OpenDialog.SetFilter('txt,png,dat,ini,inf,sys,asm,htm');
while True do
case WaitEvent of
REDRAW_EVENT:
On_Redraw;
KEY_EVENT:
case GetKey.Code of
#13{ENTER}: BrowseFile;
#32{SPACE}: BrowseDir;
else
// nothing to do
end;
BUTTON_EVENT:
if GetButton.ID = 1 then
Exit;
end;
end.
@@ -0,0 +1,70 @@
{ see original code here http://rosettacode.org/wiki/Sierpinski_triangle#Pascal }
{$APPTYPE CONSOLE}
program Sierpinski;
function ipow(b, n: Integer): Integer;
var
i: Integer;
begin
Result := 1;
for i := 1 to n do
Result := Result * b
end;
function Truth(a: Char): Boolean;
begin
if a = '*' then
Truth := True
else
Truth := False
end;
function Rule_90(ev: string): string;
var
l, i: Integer;
cp: string;
s: array[0..1] of Boolean;
begin
l := Length(ev);
cp := Copy(ev, 1, l);
for i := 1 to l do
begin
if (i-1) < 1 then
s[0] := False
else
s[0] := Truth(ev[i - 1]);
if (i+1) > l then
s[1] := False
else
s[1] := Truth(ev[i + 1]);
if (s[0] and not s[1]) or (s[1] and not s[0]) then
cp[i] := '*'
else
cp[i] := ' ';
end;
rule_90 := cp
end;
procedure Triangle(N: Integer);
var
i, l : Integer;
b : string;
begin
l := ipow(2, n + 1);
b := ' ';
for i := 1 to l do
b := b + ' ';
b[Round(l / 2)] := '*';
WriteLn(b);
for i := 1 to (Round(l / 2) - 1) do
begin
b := Rule_90(b);
WriteLn(b)
end
end;
begin
Triangle(4)
end.
@@ -0,0 +1,79 @@
{ see original code here http://rosettacode.org/wiki/Spiral_matrix#Pascal }
{$APPTYPE CONSOLE}
program Spiralmat;
type
TDir = (Left, Down, Right, Up);
TDXY = record
DX, DY: LongInt;
end;
TDeltaDir = array[TDir] of TDXY;
const
Nextdir: array[TDir] of TDir = (Down, Right, Up, Left);
cDir: TDeltaDir = ((dx: 1; dy: 0), (dx: 0; dy: 1), (dx: -1; dy: 0), (dx: 0; dy: -1));
cMaxN = 32;
type
TSpiral = array[0..cMaxN, 0..cMaxN] of LongInt;
function FillSpiral(n: LongInt): TSpiral;
var
b, i, k, dn, x, y : LongInt;
dir: TDir;
tmpSp: TSpiral;
begin
b := 0;
x := 0;
y := 0;
//only for the first line
k := -1;
dn := n - 1;
tmpSp[x, y] := b;
dir := left;
repeat
i := 0;
while i < dn do
begin
inc(b);
tmpSp[x,y] := b;
x := x + cDir[dir].dx;
y := y + cDir[dir].dy;
Inc(i);
end;
Dir := NextDir[dir];
Inc(k);
if k > 1 then
begin
k := 0;
//shorten the line every second direction change
dn := dn-1;
if dn <= 0 then
Break;
end;
until false;
//the last
tmpSp[x, y] := b + 1;
FillSpiral := tmpSp;
end;
var
a: TSpiral;
x, y, n: LongInt;
begin
for n := 1 to 5 do
begin
A := FillSpiral(n);
for y := 0 to n - 1 do
begin
for x := 0 to n - 1 do
Write(A[x, y]:4);
WriteLn;
end;
WriteLn;
end;
end.
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1,63 @@
// Factorization demo
{$APPTYPE CONSOLE}
program Factor;
var
LowBound, HighBound, Number, Dividend, Divisor: Integer;
DivisorFound: Boolean;
begin
WriteLn;
WriteLn('Integer factorization demo');
WriteLn;
Write('From number: '); ReadLn(LowBound);
Write('To number : '); ReadLn(HighBound);
WriteLn;
if LowBound < 2 then
begin
WriteLn('Numbers should be greater than 1');
ReadLn;
Halt(1);
end;
for Number := LowBound to HighBound do
begin
Write(Number, ' = ');
Dividend := Number;
while Dividend > 1 do
begin
Divisor := 1;
DivisorFound := FALSE;
while sqr(Divisor) <= Dividend do
begin
Inc(Divisor);
if Dividend mod Divisor = 0 then
begin
DivisorFound := TRUE;
Break;
end;
end;
if not DivisorFound then Divisor := Dividend; // Prime number
Write(Divisor, ' ');
Dividend := Dividend div Divisor;
end; // while
WriteLn;
end; // for
WriteLn;
WriteLn('Done.');
ReadLn;
end.
@@ -0,0 +1,7 @@
{$APPTYPE CONSOLE}
program Hello;
begin
WriteLn('Hello, World!');
end.
@@ -0,0 +1,15 @@
@echo off
if exist bin rmdir /s /q bin
mkdir bin
For /R %%i In (*.pas) Do (
..\xdpk "%%i"
)
:: Переносим все скомпилированные файлы .kex из подпапок в общую папку bin
move /y *.kex bin\
:: Если они сохраняются прямо рядом с исходниками в тех же папках, то лучше так:
:: For /R %%i In (*.kex) Do move /y "%%i" bin\
pause
@@ -0,0 +1,440 @@
// Raytracer demo - demonstrates XD Pascal methods and interfaces
{$APPTYPE CONSOLE}
program Raytracer;
type
TVec = array [1..3] of Real;
function add for u: TVec (var v: TVec): TVec;
var i: Integer;
begin
for i := 1 to 3 do Result[i] := u[i] + v[i];
end;
function sub for u: TVec (var v: TVec): TVec;
var i: Integer;
begin
for i := 1 to 3 do Result[i] := u[i] - v[i];
end;
function mul for v: TVec (a: Real): TVec;
var i: Integer;
begin
for i := 1 to 3 do Result[i] := a * v[i];
end;
function dot for u: TVec (var v: TVec): Real;
var i: Integer;
begin
Result := 0;
for i := 1 to 3 do Result := Result + u[i] * v[i];
end;
function elementwise for u: TVec (var v: TVec): TVec;
var i: Integer;
begin
for i := 1 to 3 do Result[i] := u[i] * v[i];
end;
function norm(var v: TVec): Real;
begin
Result := sqrt(v.dot(v));
end;
function normalize(var v: TVec): TVec;
begin
Result := v.mul(1.0 / norm(v));
end;
function rand: TVec;
var i: Integer;
begin
for i := 1 to 3 do Result[i] := Random - 0.5;
end;
type
TColor = TVec;
TRay = record
Origin, Dir: TVec;
end;
TGenericBody = record
Center: TVec;
Color: TColor;
Diffuseness: Real;
IsLamp: Boolean;
end;
PGenericBody = ^TGenericBody;
function LambertFactor for b: TGenericBody (Lambert: Real): Real;
begin
Result := 1.0 - (1.0 - Lambert) * b.Diffuseness;
end;
type
TBox = record
GenericBody: TGenericBody;
HalfSize: TVec;
end;
function GetGenericBody for b: TBox: PGenericBody;
begin
Result := @b.GenericBody;
end;
function Intersect for b: TBox (var Ray: TRay; var Point, Normal: TVec): Boolean;
function IntersectFace(i, j, k: Integer): Boolean;
function Within(x, y, xmin, ymin, xmax, ymax: Real): Boolean;
begin
Result := (x > xmin) and (x < xmax) and (y > ymin) and (y < ymax);
end;
var
Side, Factor: Real;
begin // IntersectFace
Result := FALSE;
if abs(Ray.Dir[k]) > 1e-9 then
begin
Side := 1.0;
if Ray.Dir[k] > 0.0 then Side := -1.0;
Factor := (b.GenericBody.Center[k] + Side * b.HalfSize[k] - Ray.Origin[k]) / Ray.Dir[k];
if Factor > 0.1 then
begin
Point := Ray.Origin.add(Ray.Dir.mul(Factor));
if Within(Point[i], Point[j],
b.GenericBody.Center[i] - b.HalfSize[i], b.GenericBody.Center[j] - b.HalfSize[j],
b.GenericBody.Center[i] + b.HalfSize[i], b.GenericBody.Center[j] + b.HalfSize[j])
then
begin
Normal[i] := 0; Normal[j] := 0; Normal[k] := Side;
Result := TRUE;
end;
end;
end;
end;
begin // Intersect
Result := IntersectFace(1, 2, 3) or IntersectFace(3, 1, 2) or IntersectFace(2, 3, 1);
end;
type
TSphere = record
GenericBody: TGenericBody;
Radius: Real;
end;
function GetGenericBody for s: TSphere: PGenericBody;
begin
Result := @s.GenericBody;
end;
function Intersect for s: TSphere (var Ray: TRay; var Point, Normal: TVec): Boolean;
var
Displacement: TVec;
Proj, Discr, Factor: Real;
begin
Displacement := s.GenericBody.Center.sub(Ray.Origin);
Proj := Displacement.dot(Ray.Dir);
Discr := sqr(s.Radius) + sqr(Proj) - Displacement.dot(Displacement);
if Discr > 0 then
begin
Factor := Proj - sqrt(Discr);
if Factor > 0.1 then
begin
Point := Ray.Origin.add(Ray.Dir.mul(Factor));
Normal := Point.sub(s.GenericBody.Center).mul(1.0 / s.Radius);
Result := TRUE;
Exit;
end;
end;
Result := FALSE;
end;
type
IBody = interface
GetGenericBody: function: PGenericBody;
Intersect: function (var Ray: TRay; var Point, Normal: TVec): Boolean;
end;
const
MAXBODIES = 10;
type
TScene = record
AmbientColor: TColor;
Body: array [1..MAXBODIES] of IBody;
NumBodies: Integer;
end;
function Trace for sc: TScene (var Ray: TRay; Depth: Integer): TColor;
var
BestBody: PGenericBody;
Point, Normal, BestPoint, BestNormal, SpecularDir, DiffuseDir: TVec;
DiffuseRay: TRay;
Dist, BestDist, Lambert: Real;
BestIndex, i: Integer;
begin
if Depth > 3 then
begin
Result := sc.AmbientColor;
Exit;
end;
// Find nearest intersection
BestDist := 1e9;
BestIndex := 0;
for i := 1 to sc.NumBodies do
begin
if sc.Body[i].Intersect(Ray, Point, Normal) then
begin
Dist := norm(Point.sub(Ray.Origin));
if Dist < BestDist then
begin
BestDist := Dist;
BestIndex := i;
BestPoint := Point;
BestNormal := Normal;
end;
end;
end;
// Reflect rays
if BestIndex > 0 then
begin
BestBody := sc.Body[BestIndex].GetGenericBody();
if BestBody^.IsLamp then
begin
Result := BestBody^.Color;
Exit;
end;
SpecularDir := Ray.Dir.sub(BestNormal.mul(2.0 * (Ray.Dir.dot(BestNormal))));
DiffuseDir := normalize(SpecularDir.add(rand.mul(2.0 * BestBody^.Diffuseness)));
Lambert := DiffuseDir.dot(BestNormal);
if Lambert < 0 then
begin
DiffuseDir := DiffuseDir.sub(BestNormal.mul(2.0 * Lambert));
Lambert := -Lambert;
end;
DiffuseRay.Origin := BestPoint;
DiffuseRay.Dir := DiffuseDir;
with BestBody^ do
Result := sc.Trace(DiffuseRay, Depth + 1).mul(LambertFactor(Lambert)).elementwise(Color);
Exit;
end;
Result := sc.AmbientColor;
end;
// Main program
const
// Define scene
Box1: TBox =
(
GenericBody:
(
Center: (500, -100, 1200);
Color: (0.4, 0.7, 1.0);
Diffuseness: 0.1;
IsLamp: FALSE
);
HalfSize: (400 / 2, 600 / 2, 300 / 2)
);
Box2: TBox =
(
GenericBody:
(
Center: (550, 210, 1100);
Color: (0.9, 1.0, 0.6);
Diffuseness: 0.3;
IsLamp: FALSE
);
HalfSize: (1000 / 2, 20 / 2, 1000 / 2)
);
Sphere1: TSphere =
(
GenericBody:
(
Center: (600, 0, 700);
Color: (1.0, 0.4, 0.6);
Diffuseness: 0.2;
IsLamp: FALSE
);
Radius: 200
);
Sphere2: TSphere =
(
GenericBody:
(
Center: (330, 150, 700);
Color: (1.0, 1.0, 0.3);
Diffuseness: 0.15;
IsLamp: FALSE
);
Radius: 50
);
// Define light
Lamp1: TSphere =
(
GenericBody:
(
Center: (500, -1000, -700);
Color: (1.0, 1.0, 1.0);
Diffuseness: 1.0;
IsLamp: TRUE
);
Radius: 800
);
AmbientLightColor: TColor = (0.2, 0.2, 0.2);
// Define eye
Pos: TVec = (0, 0, 0);
Azimuth = 30.0 * pi / 180.0;
Width = 640;
Height = 480;
Focal = 500;
Antialiasing = 1.0;
// Output file
FileName = 'scene.ppm';
var
Scene: TScene;
Dir, RotDir, RandomDir: TVec;
Color: TColor;
Ray: TRay;
sinAz, cosAz: Real;
F: Text;
Rays, i, j, r: Integer;
StartTime, StopTime: LongInt;
Buf: array [0..Width * Height * 3 - 1] of Byte;
BufPos: LongInt = 0;
begin
WriteLn('Raytracer demo');
WriteLn;
Write('Rays per pixel (recommended 1 to 100): '); ReadLn(Rays);
WriteLn;
Randomize;
with Scene do
begin
AmbientColor := AmbientLightColor;
Body[1] := Box1;
Body[2] := Box2;
Body[3] := Sphere1;
Body[4] := Sphere2;
Body[5] := Lamp1;
NumBodies := 5;
end;
sinAz := sin(Azimuth); cosAz := cos(Azimuth);
Assign(F, FileName);
Rewrite(F);
Write(F, 'P6 ');
Write(F, Width, ' ', Height, ' ');
Write(F, 255, ' ');
StartTime := GetTickCount;
for i := 0 to Height - 1 do
begin
for j := 0 to Width - 1 do
begin
Color[1] := 0;
Color[2] := 0;
Color[3] := 0;
Dir[1] := j - Width / 2;
Dir[2] := i - Height / 2;
Dir[3] := Focal;
RotDir[1] := Dir[1] * cosAz + Dir[3] * sinAz;
RotDir[2] := Dir[2];
RotDir[3] := -Dir[1] * sinAz + Dir[3] * cosAz;
for r := 1 to Rays do
begin
RandomDir := RotDir.add(rand.mul(Antialiasing));
Ray.Origin := Pos;
Ray.Dir := normalize(RandomDir);
Color := Color.add(Scene.Trace(Ray, 0));
end;
Color := Color.mul(255.0 / Rays);
Buf[BufPos] := Round(Color[1]);
Buf[BufPos + 1] := Round(Color[2]);
Buf[BufPos + 2] := Round(Color[3]);
BufPos := BufPos + 3;
end;
WriteLn(i + 1, '/', Height);
end;
BlockWrite(F, Buf, SizeOf(Buf));
StopTime := GetTickCount;
Close(F);
WriteLn;
WriteLn('Rendering time: ', (StopTime - StartTime) / 1000 :5:1, ' s');
WriteLn('Done. See ' + FileName);
ReadLn;
end.
@@ -0,0 +1,243 @@
// Sorting demo
{$APPTYPE CONSOLE}
program Sort;
type
TValue = Integer;
TCompareFunc = function(x, y: TValue): Boolean;
procedure Swap(var x, y: TValue);
var
buf: TValue;
begin
buf := x;
x := y;
y := buf;
end;
procedure QuickSort(var data: array of TValue; len: Integer; Ordered: TCompareFunc);
function Partition(var data: array of TValue; low, high: Integer; Ordered: TCompareFunc): Integer;
var
pivot: TValue;
pivotIndex, i: Integer;
begin
pivot := data[high];
pivotIndex := low;
for i := low to high - 1 do
if not Ordered(data[i], pivot) then
begin
Swap(data[pivotIndex], data[i]);
Inc(pivotIndex);
end; // if
Swap(data[high], data[pivotIndex]);
Result := pivotIndex;
end;
procedure Sort(var data: array of TValue; low, high: Integer; Ordered: TCompareFunc);
var
pivotIndex: Integer;
begin
if high > low then
begin
pivotIndex := Partition(data, low, high, Ordered);
Sort(data, low, pivotIndex - 1, Ordered);
Sort(data, pivotIndex + 1, high, Ordered);
end; // if
end;
begin
Sort(data, 0, len - 1, Ordered);
end;
procedure BubbleSort(var data: array of TValue; len: Integer; Ordered: TCompareFunc);
var
changed: Boolean;
i: Integer;
begin
repeat
changed := FALSE;
for i := 0 to len - 2 do
if not Ordered(data[i + 1], data[i]) then
begin
Swap(data[i + 1], data[i]);
changed := TRUE;
end;
until not changed;
end;
procedure SelectionSort(var data: array of TValue; len: Integer; Ordered: TCompareFunc);
var
i, j, extrIndex: Integer;
extr: TValue;
begin
for i := 0 to len - 1 do
begin
extr := data[i];
extrIndex := i;
for j := i + 1 to len - 1 do
if not Ordered(data[j], extr) then
begin
extr := data[j];
extrIndex := j;
end;
Swap(data[i], data[extrIndex]);
end; // for
end;
function Sorted(var data: array of TValue; len: Integer; Ordered: TCompareFunc): Boolean;
var
i: Integer;
begin
Result := TRUE;
for i := 0 to len - 2 do
if not Ordered(data[i + 1], data[i]) then
begin
Result := FALSE;
Break;
end;
end;
function OrderedAscending(y, x: TValue): Boolean;
begin
Result := y >= x;
end;
function OrderedDescending(y, x: TValue): Boolean;
begin
Result := y <= x;
end;
const
DataLength = 600;
var
RandomData: array [1..DataLength] of TValue;
i: Integer;
Ordered: TCompareFunc;
Order, Method: Char;
begin
WriteLn;
WriteLn('Sorting demo');
WriteLn;
WriteLn('Initial array: ');
WriteLn;
Randomize;
for i := 1 to DataLength do
begin
RandomData[i] := Round((Random - 0.5) * 1000000);
Write(RandomData[i]: 8);
if i mod 6 = 0 then WriteLn;
end;
WriteLn;
WriteLn;
Write('Select order (A - ascending, D - descending): '); ReadLn(Order);
WriteLn;
case Order of
'A', 'a':
begin
WriteLn('Ascending order');
Ordered := @OrderedAscending;
end;
'D', 'd':
begin
WriteLn('Descending order');
Ordered := @OrderedDescending;
end
else
WriteLn('Order is not selected.');
Ordered := nil;
ReadLn;
Halt;
end;
WriteLn;
Write('Select method (Q - quick, B - bubble, S - selection): '); ReadLn(Method);
WriteLn;
case Method of
'Q', 'q':
begin
WriteLn('Quick sorting');
QuickSort(RandomData, DataLength, Ordered);
end;
'B', 'b':
begin
WriteLn('Bubble sorting');
BubbleSort(RandomData, DataLength, Ordered);
end;
'S', 's':
begin
WriteLn('Selection sorting');
SelectionSort(RandomData, DataLength, Ordered);
end
else
WriteLn('Sorting method is not selected.');
ReadLn;
Halt;
end;
WriteLn;
WriteLn('Sorted array: ');
WriteLn;
for i := 1 to DataLength do
begin
Write(RandomData[i]: 8);
if i mod 6 = 0 then WriteLn;
end;
WriteLn;
WriteLn('Sorted: ', Sorted(RandomData, DataLength, Ordered));
WriteLn('Done.');
ReadLn;
end.
@@ -0,0 +1,307 @@
program TorusDemo;
uses
KolibriOS, TinyGL;
const
MAX_VERTICES = 20000;
MAX_FACES = 20000;
type
TVertex = record
x, y, z: Single;
r, g, b: Byte;
end;
TFace = record
v1, v2, v3, v4: TVertex;
avgZ: Single;
colorR, colorG, colorB: Byte;
end;
var
WndLeft, WndTop, WndWidth, WndHeight: LongInt;
CTX: TKOSGLContext;
MainRadius, BaseTubeRadius: Single;
TorusSegments, TubeSegments, WaveCount: Integer;
ProjectedVertices: array[0..MAX_VERTICES - 1] of TVertex;
Faces: array[0..MAX_FACES - 1] of TFace;
TotalVerticesCount, TotalFacesCount: Integer;
AngleX: Single = 0.6;
AngleY: Single = 0.5;
TimeColor: Single = 0.0;
TimeScale: Single = 0.0;
// яЁюЎхфєЁр яхЁёяхъЄштэющ ьрЄЁшЎ√
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
function Min(A, B: Extended): Extended;
begin
if A < B then Result := A else Result := B;
end;
function Max(A, B: Extended): Extended;
begin
if A > B then Result := A else Result := B;
end;
function Power(Base, Exponent: Extended): Extended;
begin
Result := Exp(Exponent * Ln(Base));
end;
procedure ResizeTopology(W, H: Integer);
begin
MainRadius := H / 4.85;
BaseTubeRadius := MainRadius / 2.45;
TorusSegments := Round(H / 10);
TubeSegments := Round(H / 15);
WaveCount := Round(H / 100);
if TorusSegments < 16 then TorusSegments := 16;
if TubeSegments < 8 then TubeSegments := 8;
if WaveCount < 3 then WaveCount := 3;
TotalVerticesCount := (TorusSegments + 1) * (TubeSegments + 1);
TotalFacesCount := TorusSegments * TubeSegments;
// ╟р∙шЄр юЄ яхЁхяюыэхэш  ёЄрЄшўхёъюую сєЇхЁр
if TotalVerticesCount > MAX_VERTICES then TotalVerticesCount := MAX_VERTICES;
if TotalFacesCount > MAX_FACES then TotalFacesCount := MAX_FACES;
end;
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
I, J, Idx, Stride: Integer;
U, V, Wave1, Wave2, CurrentTubeRadius, SpineWave: Single;
CosU, SinU, CosV, SinV, CosX, SinX, CosY, SinY: Single;
X, Y, Z, X1, Z1, Y2, Z2, Factor, Fov: Single;
CamDist, CenterX, CenterY: Single;
Idx1, Idx2, Idx3, Idx4: Integer;
P1, P2, P3, P4: TVertex;
AX, AY, AZ, BX, BY, BZ, NX, NY, NZ, Len: Single;
RFinal, GFinal, BFinal: Single;
ViewDot, Rim, CenterDarkness: Single;
NormX, NormY, NormZ: Single;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
if not (ThreadInfo.Client.Height > 3) then Exit;
kosglMakeCurrent(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height, CTX);
glViewPort(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glClearColor(10/255, 10/255, 10/255, 0.0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
// ╤ўшЄрхь °руш ёхЄъш
ResizeTopology(ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(45.0, ThreadInfo.Client.Width / ThreadInfo.Client.Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
CamDist := 500.0;
CenterX := ThreadInfo.Client.Width / 2.0;
CenterY := ThreadInfo.Client.Height / 2.0;
Fov := Min(ThreadInfo.Client.Width, ThreadInfo.Client.Height) * 1.1;
CosY := Cos(AngleY); SinY := Sin(AngleY);
CosX := Cos(AngleX); SinX := Sin(AngleX);
// === ╪ру 1: ╠рЄхьрЄшўхёъшщ ЁрёўхЄ тюыэютюую ЄюЁр ===
Idx := 0;
for I := 0 to TorusSegments do
begin
U := (I / TorusSegments) * PI * 2.0;
Wave1 := Sin(U * WaveCount + TimeScale) * (BaseTubeRadius * 0.44);
Wave2 := Cos(U * (WaveCount * 2) - TimeScale * 1.5) * (BaseTubeRadius * 0.17);
CurrentTubeRadius := BaseTubeRadius + Wave1 + Wave2;
SpineWave := Sin(U * 3.0 - TimeScale * 1.2) * (MainRadius * 0.25);
CosU := Cos(U); SinU := Sin(U);
for J := 0 to TubeSegments do
begin
if Idx >= MAX_VERTICES then Break;
V := (J / TubeSegments) * PI * 2.0;
CosV := Cos(V); SinV := Sin(V);
X := (MainRadius + CurrentTubeRadius * CosV) * CosU;
Y := CurrentTubeRadius * SinV + SpineWave;
Z := (MainRadius + CurrentTubeRadius * CosV) * SinU;
X1 := X * CosY - Z * SinY;
Z1 := X * SinY + Z * CosY;
Y2 := Y * CosX - Z1 * SinX;
Z2 := Y * SinX + Z1 * CosX;
Factor := Fov / (Z2 + CamDist);
ProjectedVertices[Idx].x := CenterX + X1 * Factor;
ProjectedVertices[Idx].y := CenterY + Y2 * Factor;
ProjectedVertices[Idx].z := Z2;
ProjectedVertices[Idx].r := Round((Sin(X * 0.015 + TimeColor) * 0.5 + 0.5) * 255.0);
ProjectedVertices[Idx].g := Round((Sin(Y * 0.015 + TimeColor * 1.4) * 0.5 + 0.5) * 255.0);
ProjectedVertices[Idx].b := Round((Cos(Z * 0.015 + TimeColor) * 0.5 + 0.5) * 255.0);
Inc(Idx);
end;
end;
// === ╪ру 2: ╤сюЁър ўхЄ√Ёхїєуюы№э√ї уЁрэхщ ш Rim Lighting ===
Stride := TubeSegments + 1;
Idx := 0;
for I := 0 to TorusSegments - 1 do
begin
for J := 0 to TubeSegments - 1 do
begin
if Idx >= MAX_FACES then Break;
Idx1 := I * Stride + J;
Idx2 := (I + 1) * Stride + J;
Idx3 := (I + 1) * Stride + (J + 1);
Idx4 := I * Stride + (J + 1);
if (Idx1 >= MAX_VERTICES) or (Idx2 >= MAX_VERTICES) or
(Idx3 >= MAX_VERTICES) or (Idx4 >= MAX_VERTICES) then Continue;
P1 := ProjectedVertices[Idx1];
P2 := ProjectedVertices[Idx2];
P3 := ProjectedVertices[Idx3];
P4 := ProjectedVertices[Idx4];
AX := P2.x - P1.x; AY := P2.y - P1.y; AZ := P2.z - P1.z;
BX := P4.x - P1.x; BY := P4.y - P1.y; BZ := P4.z - P1.z;
NX := AY * BZ - AZ * BY;
NY := AZ * BX - ax * BZ;
NZ := AX * BY - AY * BX;
Len := Sqrt(NX * NX + NY * NY + NZ * NZ);
RFinal := P1.r; GFinal := P1.g; BFinal := P1.b;
if Len > 0.0 then
begin
NZ := NZ / Len;
ViewDot := Abs(NZ);
Rim := Power(1.0 - ViewDot, 3) * 1.5;
CenterDarkness := Max(0.15, ViewDot * 0.5);
RFinal := (P1.r * CenterDarkness) + (P1.r * Rim);
GFinal := (P1.g * CenterDarkness) + (P1.g * Rim);
BFinal := (P1.b * CenterDarkness) + (P1.b * Rim);
if RFinal > 255.0 then RFinal := 255.0;
if GFinal > 255.0 then GFinal := 255.0;
if BFinal > 255.0 then BFinal := 255.0;
end;
Faces[Idx].v1 := P1;
Faces[Idx].v2 := P2;
Faces[Idx].v3 := P3;
Faces[Idx].v4 := P4;
Faces[Idx].avgZ := (P1.z + P2.z + P3.z + P4.z) * 0.25;
Faces[Idx].colorR := Round(RFinal);
Faces[Idx].colorG := Round(GFinal);
Faces[Idx].colorB := Round(BFinal);
Inc(Idx);
end;
end;
// ╬ЄЁшёютър т ёЄрэфрЁЄэюь яхЁёяхъЄштэюь 3D-яЁюёЄЁрэёЄтх
// ╤фтшурхь ёЎхэє эрчрф яю юёш Z, ўЄюс√ ухюьхЄЁш  яюыэюёЄ№■ тю°ыр т яшЁрьшфє Frustum
glTranslatef(0.0, 0.0, -4.7);
// === ╪ру 4: ┬шчєрышчрЎш  яюышуюэют ёЁхфёЄтрьш TinyGL ===
for I := 0 to TotalFacesCount - 1 do
begin
glBegin(GL_QUADS);
glColor3f(Faces[I].colorR / 255.0, Faces[I].colorG / 255.0, Faces[I].colorB / 255.0);
// яхЁхтюфшь яшъёхыш т фшрярчюэ (-1.0..1.0)
// ┬ glVertex3f яхЁхфрхЄё  уыєсшэр NormZ
NormX := (Faces[I].v1.x / ThreadInfo.Client.Width) * 2.0 - 1.0;
NormY := 1.0 - (Faces[I].v1.y / ThreadInfo.Client.Height) * 2.0;
NormZ := -((Faces[I].v1.z + 250.0) / 500.0); // ╠рё°ЄрсшЁєхь Z т ърэюэшўхёъшщ фшрярчюэ тшфшьюёЄш
glVertex3f(NormX * 1.95, NormY * 1.45, NormZ);
NormX := (Faces[I].v2.x / ThreadInfo.Client.Width) * 2.0 - 1.0;
NormY := 1.0 - (Faces[I].v2.y / ThreadInfo.Client.Height) * 2.0;
NormZ := -((Faces[I].v2.z + 250.0) / 500.0);
glVertex3f(NormX * 1.95, NormY * 1.45, NormZ);
NormX := (Faces[I].v3.x / ThreadInfo.Client.Width) * 2.0 - 1.0;
NormY := 1.0 - (Faces[I].v3.y / ThreadInfo.Client.Height) * 2.0;
NormZ := -((Faces[I].v3.z + 250.0) / 500.0);
glVertex3f(NormX * 1.95, NormY * 1.45, NormZ);
NormX := (Faces[I].v4.x / ThreadInfo.Client.Width) * 2.0 - 1.0;
NormY := 1.0 - (Faces[I].v4.y / ThreadInfo.Client.Height) * 2.0;
NormZ := -((Faces[I].v4.z + 250.0) / 500.0);
glVertex3f(NormX * 1.95, NormY * 1.45, NormZ);
glEnd();
end;
kosglSwapBuffers();
// === ╪ру 5: ╚эъЁхьхэЄ °руют рэшьрЎшш ш фшэрьшўхёъшї Їрчют√ї ёфтшуют ===
AngleX := AngleX + 0.01;
AngleY := AngleY + 0.02;
TimeColor := TimeColor + 0.02;
TimeScale := TimeScale + 0.1;
end;
begin
TinyGL_initialization;
with GetScreenSize do
begin
WndWidth := Width div 3 * 2;
WndHeight := Height div 3 * 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'TinyGL Torus Demo', $00FFFFFF,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
GLDraw;
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
ExitThread;
else
GLDraw;
end;
end.
@@ -0,0 +1,368 @@
program CircleParticlesTinyGL;
uses
KolibriOS, TinyGL;
const
// ╠ръёшьры№эюх ъюышўхёЄтю ўрёЄшЎ
MAX_PARTICLES = 3000;
// ╩юышўхёЄтю эют√ї ўрёЄшЎ чр ърфЁ
SPAWN_PER_FRAME = 18;
// ╨рчьхЁ ярышЄЁ√
PALETTE_SIZE = 64;
// ╩юышўхёЄтю ёхуьхэЄют ъЁєур
CIRCLE_SEGMENTS = 12;
// ╙уюы юсчюЁр яхЁёяхъЄшт√
FIELD_OF_VIEW = 45.0;
type
// ╫рёЄшЎр
TParticle = record
Life: LongInt;
X, Y: GLFloat;
VX, VY: GLFloat;
Radius: GLFloat;
end;
// ╓тхЄ ярышЄЁ√
TPaletteColor = record
R, G, B: GLFloat;
end;
var
// ╩юэЄхъёЄ TinyGL
CTX: TKOSGLContext;
// ╧єы ўрёЄшЎ
Particles: array[0..MAX_PARTICLES - 1] of TParticle;
// ╨рфєцэр  ярышЄЁр
RainbowPalette: array[0..PALETTE_SIZE - 1] of TPaletteColor;
// ╩єЁёюЁ яюшёър ётюсюфэющ ўрёЄшЎ√
PoolCursor: LongInt = 0;
// ╤ў╕Єўшъ ърфЁют
FrameCounter: LongInt = 0;
// ╨рчьхЁ√ ш яюыюцхэшх юъэр
WndLeft, WndTop, WndWidth, WndHeight: LongInt;
// ═рёЄЁющър яхЁёяхъЄшт√ ърьхЁ√
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
// ╤ыєўрщэюх Float ўшёыю
function RandomFloat(MinValue, MaxValue: GLFloat): GLFloat;
begin
RandomFloat :=
MinValue +
Random * (MaxValue - MinValue);
end;
// HSV -> RGB
procedure HSVtoRGB(H, S, V: GLFloat; var R, G, B: GLFloat);
var
I: LongInt;
F, P, Q, T: GLFloat;
begin
H := H * 6.0;
I := Trunc(H);
F := H - I;
P := V * (1.0 - S);
Q := V * (1.0 - S * F);
T := V * (1.0 - S * (1.0 - F));
case I mod 6 of
0: begin R := V; G := T; B := P; end;
1: begin R := Q; G := V; B := P; end;
2: begin R := P; G := V; B := T; end;
3: begin R := P; G := Q; B := V; end;
4: begin R := T; G := P; B := V; end;
else
begin R := V; G := P; B := Q; end;
end;
end;
// ╨рфєцэр  ярышЄЁр
procedure BuildRainbowPalette;
var
I: LongInt;
H: GLFloat;
begin
for I := 0 to PALETTE_SIZE - 1 do
begin
H := 1 - I / (PALETTE_SIZE - 1);
HSVtoRGB(
H,
1.0,
1.0,
RainbowPalette[I].R,
RainbowPalette[I].G,
RainbowPalette[I].B
);
end;
end;
// ╨шёютрэшх ъЁєуыющ ўрёЄшЎ√
procedure DrawParticleCircle(X, Y, Radius: GLFloat);
var
I: LongInt;
Angle, PX, PY: GLFloat;
begin
glBegin(GL_TRIANGLE_FAN);
// ╓хэЄЁ ъЁєур
glVertex3f(X, Y, 0.0);
// ╬ъЁєцэюёЄ№
for I := 0 to CIRCLE_SEGMENTS do
begin
Angle := (PI * 2.0 * I) / CIRCLE_SEGMENTS;
PX := X + Cos(Angle) * Radius;
PY := Y + Sin(Angle) * Radius;
glVertex3f(PX, PY, 0.0);
end;
glEnd();
end;
// ╤ючфрэшх ўрёЄшЎ√
procedure SpawnParticle(EmitX, EmitY: GLFloat);
var
Attempts: LongInt;
P: ^TParticle;
Angle,
Speed: GLFloat;
begin
Attempts := MAX_PARTICLES;
while Attempts > 0 do
begin
P := @Particles[PoolCursor];
PoolCursor :=
(PoolCursor + 1) mod MAX_PARTICLES;
if P^.Life <= 0 then
begin
Angle := RandomFloat(0.0, PI * 2.0);
Speed := RandomFloat(5.0, 13.0);
P^.X := EmitX;
P^.Y := EmitY;
P^.VX := Cos(Angle) * Speed;
P^.VY := Sin(Angle) * Speed - 7.0;
P^.Life := Round(40 + Random * 24);
P^.Radius := 1 + Random * 3;
Exit;
end;
Dec(Attempts);
end;
end;
// ╬ёэютэющ ЁхэфхЁ
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
Width,
Height: LongInt;
CameraZ, EmitX,
EmitY: GLFloat;
I: LongInt;
P: ^TParticle;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
Width := ThreadInfo.Client.Width;
Height := ThreadInfo.Client.Height;
if Height <= 3 then Exit;
kosglMakeCurrent(0, 0, Width, Height, CTX);
glViewPort( 0, 0, Width, Height);
// ╧хЁт√щ ърфЁ яюыэюёЄ№■ юўш∙рхЄ ¤ъЁрэ
if FrameCounter = 0 then
begin
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
end;
// ═рёЄЁющър яхЁёяхъЄшт√
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(
FIELD_OF_VIEW,
Width / Height,
0.1,
5000.0
);
// ─шэрьшўхёър  ърьхЁр
// ╨рчьхЁ ёЎхэ√ ёЄрсшыхэ яЁш ы■сюь ЁрчьхЁх юъэр
CameraZ :=
Height /
(Sin(FIELD_OF_VIEW * PI / 360.0) /
Cos(FIELD_OF_VIEW * PI / 360.0));
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(
-Width * 0.5,
-Height * 0.5,
-CameraZ * 0.5
);
// ╧юыюцхэшх ¤ьшЄЄхЁр
// ╬ЄёЄєя√ ёЄрсшы№э√ яЁш ы■сюь ЁрчьхЁх юъэр
EmitX :=
(Width * 0.5) +
Sin(FrameCounter * 0.03) *
(Width * 0.46);
EmitY :=
(Height * 0.5) +
Cos(FrameCounter * 0.02) *
(Height * 0.44);
// ╤ючфрэшх эют√ї ўрёЄшЎ
for I := 0 to SPAWN_PER_FRAME - 1 do
SpawnParticle(EmitX, EmitY);
// ╬сэютыхэшх ўрёЄшЎ
for I := 0 to MAX_PARTICLES - 1 do
begin
P := @Particles[I];
if P^.Life <= 0 then
Continue;
// ─тшцхэшх
P^.X := P^.X + P^.VX;
P^.Y := P^.Y + P^.VY;
// ├ЁртшЄрЎш 
P^.VY := P^.VY + 0.18;
// ╬Єёъюъ юЄ ёЄхэюъ
if P^.X > Width - P^.Radius then
begin
P^.X := Width - P^.Radius;
P^.VX := P^.VX * (-0.80);
end;
if P^.X < P^.Radius then
begin
P^.X := P^.Radius;
P^.VX := P^.VX * (-0.80);
end;
// ╬Єёъюъ юЄ яюЄюыър ш яюыр
if P^.Y > Height - P^.Radius then
begin
P^.Y := Height - P^.Radius;
P^.VY := P^.VY * (-0.70);
P^.VX := P^.VX * 0.94;
end;
if P^.Y < P^.Radius then
begin
P^.Y := P^.Radius;
P^.VY := P^.VY * (-0.70);
P^.VX := P^.VX * 0.94;
end;
// ╙ьхэ№°хэшх цшчэш
Dec(P^.Life);
if P^.Life > 0 then
begin
glColor3f(
RainbowPalette[P^.Life].R,
RainbowPalette[P^.Life].G,
RainbowPalette[P^.Life].B
);
DrawParticleCircle(
P^.X,
P^.Y,
P^.Radius
);
end;
end;
// ┬√тюф ърфЁр
kosglSwapBuffers();
Inc(FrameCounter);
end;
begin
TinyGL_initialization;
Randomize;
BuildRainbowPalette;
with GetScreenSize do
begin
WndWidth := Width div 2;
WndHeight := Height div 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
begin
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(
WndLeft,
WndTop,
WndWidth,
WndHeight,
'Circle Particles TinyGL',
$00000000,
WS_SKINNED_SIZABLE +
WS_CLIENT_COORDS +
WS_CAPTION,
CAPTION_MOVABLE
);
GLDraw;
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
ExitThread;
else
GLDraw;
end;
end;
end.
@@ -0,0 +1,169 @@
program DNAHelix3D;
uses
KolibriOS, TinyGL;
const
MAX_ELEMENTS = 40; { ╩юышўхёЄтю ёЄєяхэхщ т Ўхяюўъх ─═╩ }
RADIUS = 1.1; { ╨рфшєё чръЁєўштрэш  ёяшЁрыш }
STEP_HEIGHT = 0.12; { ╨рёёЄю эшх ьхцфє ёЄєяхэ ьш яю тхЁЄшърыш }
type
TBaseNode = record
X1, Y1, Z1: GLFloat;
X2, Y2, Z2: GLFloat;
R, G, B: GLFloat;
end;
var
Nodes: array[1..MAX_ELEMENTS] of TBaseNode;
Rotation: GLFloat = 0;
Speed: GLFloat = 0.5;
ZTr: GLFloat = -7.5;
TimeVal: GLFloat = 0;
CTX: TKOSGLContext;
WndLeft, WndTop, WndWidth, WndHeight: LongInt;
// ═рёЄЁющър яхЁёяхъЄшт√ ърьхЁ√
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
{ ╠рЄхьрЄшўхёъшщ ЁрёўхЄ тюыэютюую ёъЁєўштрэш  ш фхЇюЁьрЎшш ─═╩ }
procedure UpdateDNAPhysics;
var
I: Integer;
Angle, VertPos, Wave: GLFloat;
begin
for I := 1 to MAX_ELEMENTS do
begin
{ ┴рчют√щ єуюы чръЁєўштрэш  + фшэрьшўхёър  тюыэр тЁхьхэш }
Angle := (I * 0.4) + Sin(TimeVal + I * 0.15) * 0.25;
VertPos := (I - (MAX_ELEMENTS div 2)) * STEP_HEIGHT;
{ ╥хяыютющ тюыэютющ °єь }
Wave := Cos(TimeVal * 2.0 + I * 0.1) * 0.08;
{ ═шЄ№ └ ёяшЁрыш }
Nodes[I].X1 := Cos(Angle) * (RADIUS + Wave);
Nodes[I].Y1 := VertPos;
Nodes[I].Z1 := Sin(Angle) * (RADIUS + Wave);
{ ═шЄ№ ┴ ёяшЁрыш (яЁюЄштюЇрчр 180 уЁрфєёют / PI) }
Nodes[I].X2 := Cos(Angle + 3.14159) * (RADIUS + Wave);
Nodes[I].Y2 := VertPos;
Nodes[I].Z2 := Sin(Angle + 3.14159) * (RADIUS + Wave);
{ ╓тхЄютюх ъюфшЁютрэшх эєъыхюЄшфют т чртшёшьюёЄш юЄ т√ёюЄ√ }
Nodes[I].R := 0.4 + Sin(I * 0.2) * 0.4;
Nodes[I].G := 0.2 + Cos(I * 0.1) * 0.4;
Nodes[I].B := 0.8 - Sin(I * 0.05) * 0.2;
end;
end;
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
I: Integer;
S: GLFloat;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
if ThreadInfo.Client.Height <= 3 then Exit;
kosglMakeCurrent(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height, CTX);
glViewPort(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glClearColor(0.15, 0.15, 0.3, 0.0); { ├ыєсюъшщ сшю-ъшсхЁэхЄшўхёъшщ Їюэ }
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(45.0, ThreadInfo.Client.Width / ThreadInfo.Client.Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, ZTr);
glRotatef(Rotation, 0.3, 1.0, 0.1); { ╧ыртэ√щ юсыхЄ ърьхЁ√ }
S := 0.06; { ╥юы∙шэр єчыют }
for I := 1 to MAX_ELEMENTS do
begin
{ 1. ╨шёєхь яхЁхь√ўъш ьхцфє эшЄ ьш ─═╩ }
glBegin(GL_QUADS);
glColor3f(Nodes[I].R * 0.6, Nodes[I].G * 0.6, Nodes[I].B * 0.6);
glVertex3f(Nodes[I].X1, Nodes[I].Y1 - 0.02, Nodes[I].Z1);
glVertex3f(Nodes[I].X2, Nodes[I].Y2 - 0.02, Nodes[I].Z2);
glVertex3f(Nodes[I].X2, Nodes[I].Y2 + 0.02, Nodes[I].Z2);
glVertex3f(Nodes[I].X1, Nodes[I].Y1 + 0.02, Nodes[I].Z1);
glEnd();
{ 2. ╨шёєхь ёЇхЁє-ъєсшъ эшЄш └ }
glBegin(GL_QUADS);
glColor3f(Nodes[I].R, Nodes[I].G, Nodes[I].B);
glVertex3f(Nodes[I].X1 - S, Nodes[I].Y1 - S, Nodes[I].Z1 + S);
glVertex3f(Nodes[I].X1 + S, Nodes[I].Y1 - S, Nodes[I].Z1 + S);
glVertex3f(Nodes[I].X1 + S, Nodes[I].Y1 + S, Nodes[I].Z1 + S);
glVertex3f(Nodes[I].X1 - S, Nodes[I].Y1 + S, Nodes[I].Z1 + S);
glEnd();
{ 3. ╨шёєхь ёЇхЁє-ъєсшъ эшЄш ┴ }
glBegin(GL_QUADS);
glColor3f(Nodes[I].B, Nodes[I].R, Nodes[I].G); { ╚этхЁЄшЁютрээ√щ ЎтхЄ фы  ярЁ√ }
glVertex3f(Nodes[I].X2 - S, Nodes[I].Y2 - S, Nodes[I].Z2 + S);
glVertex3f(Nodes[I].X2 + S, Nodes[I].Y2 - S, Nodes[I].Z2 + S);
glVertex3f(Nodes[I].X2 + S, Nodes[I].Y2 + S, Nodes[I].Z2 + S);
glVertex3f(Nodes[I].X2 - S, Nodes[I].Y2 + S, Nodes[I].Z2 + S);
glEnd();
end;
kosglSwapBuffers();
UpdateDNAPhysics;
Rotation := Rotation + Speed;
TimeVal := TimeVal + 0.03;
end;
begin
TinyGL_initialization;
with GetScreenSize do
begin
WndWidth := Width div 3 * 2;
WndHeight := Height div 3 * 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, '3D DNA Helix Wave', $00FFFFFF,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
GLDraw;
EndDraw;
end;
KEY_EVENT: GetKey;
BUTTON_EVENT: if GetButton.ID = 1 then ExitThread;
else
GLDraw;
end;
end.
@@ -0,0 +1,181 @@
program FractalStormForest;
uses
KolibriOS, TinyGL;
const
NUM_TREES = 7; // ъюышўхёЄтю фхЁхт№хт
MAX_DEPTH = 5; // уыєсшэр ЇЁръЄрыр
var
Rotation: GLFloat = 0;
Speed: GLFloat = 0.5;
ZTr: GLFloat = -11.0;
TimeVal: GLFloat = 0;
CTX: TKOSGLContext;
WndLeft, WndTop, WndWidth, WndHeight: LongInt;
// ═рёЄЁющър яхЁёяхъЄшт√ ърьхЁ√
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
procedure DrawBranch(Length: GLFloat; Depth: Integer; WindForce: GLFloat);
var
R, G, B: GLFloat;
begin
if Depth > MAX_DEPTH then Exit;
// ╬╤┼══▀▀ ╧└╦╚╥╨└ ╦╚╤╥┬█
// ╤Єтюы Єхьэю-сюЁфют√щ }
// ╩Ёюэр  Ёъю-чюыюЄр  / юЁрэцхтр  }
R := 0.3 + (Depth * 0.18);
G := 0.05 + (Depth * 0.18);
B := 0.1;
glBegin(GL_QUADS);
glColor3f(R, G, B);
glVertex3f(-0.1 * Length, 0.0, 0.1 * Length);
glVertex3f( 0.1 * Length, 0.0, 0.1 * Length);
glVertex3f( 0.05 * Length, Length, 0.05 * Length);
glVertex3f(-0.05 * Length, Length, 0.05 * Length);
glColor3f(R * 0.8, G * 0.8, B * 0.8);
glVertex3f( 0.1 * Length, 0.0, 0.1 * Length);
glVertex3f( 0.1 * Length, 0.0, -0.1 * Length);
glVertex3f( 0.05 * Length, Length, -0.05 * Length);
glVertex3f( 0.05 * Length, Length, 0.05 * Length);
glColor3f(R * 0.6, G * 0.6, B * 0.6);
glVertex3f( 0.1 * Length, 0.0, -0.1 * Length);
glVertex3f(-0.1 * Length, 0.0, -0.1 * Length);
glVertex3f(-0.05 * Length, Length, -0.05 * Length);
glVertex3f( 0.05 * Length, Length, -0.05 * Length);
glColor3f(R * 0.7, G * 0.7, B * 0.7);
glVertex3f(-0.1 * Length, 0.0, -0.1 * Length);
glVertex3f(-0.1 * Length, 0.0, 0.1 * Length);
glVertex3f(-0.05 * Length, Length, 0.05 * Length);
glVertex3f(-0.05 * Length, Length, -0.05 * Length);
glEnd();
glTranslatef(0.0, Length, 0.0);
glPushMatrix();
glRotatef(22.0 + WindForce, 1.0, 0.0, 0.0);
glRotatef(20.0, 0.0, 0.0, 1.0);
glScalef(0.75, 0.75, 0.75);
DrawBranch(Length, Depth + 1, WindForce * 1.25);
glPopMatrix();
glPushMatrix();
glRotatef(-22.0 + WindForce, 1.0, 0.0, 0.0);
glRotatef(-20.0, 0.0, 0.0, 1.0);
glScalef(0.75, 0.75, 0.75);
DrawBranch(Length, Depth + 1, WindForce * 1.25);
glPopMatrix();
glPushMatrix();
glRotatef(30.0, 0.0, 1.0, 0.0);
glRotatef(15.0 + WindForce, 0.0, 0.0, 1.0);
glScalef(0.7, 0.7, 0.7);
DrawBranch(Length, Depth + 1, WindForce * 1.15);
glPopMatrix();
end;
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
I: Integer;
TreeAngle, Wind: GLFloat;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
if ThreadInfo.Client.Height <= 3 then Exit;
kosglMakeCurrent(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height, CTX);
glViewPort(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glClearColor(0.04, 0.04, 0.08, 0.0); // ╚ёёшэ -ўхЁэюх эхсю
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(45.0, ThreadInfo.Client.Width / ThreadInfo.Client.Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, -1.2, ZTr);
glRotatef(Rotation, 0.0, 1.0, 0.0);
glBegin(GL_QUADS);
glColor3f(0.35, 0.30, 0.20);
glVertex3f(-4.0, -1.0, 4.0); glVertex3f( 4.0, -1.0, 4.0);
glVertex3f( 4.0, -1.0, -4.0); glVertex3f(-4.0, -1.0, -4.0);
glEnd();
// ╧╬╨█┬╚╤╥█╔ ┬┼╥┼╨
Wind := (Sin(TimeVal * 0.8) * 6.0) + (Sin(TimeVal * 2.5) * 3.5) + (Sin(TimeVal * 6.0) * 1.5);
for I := 0 to NUM_TREES - 1 do
begin
glPushMatrix();
TreeAngle := (I * 360.0) / NUM_TREES;
glRotatef(TreeAngle, 0.0, 1.0, 0.0);
glTranslatef(0.0, -1.0, 2.2);
DrawBranch(2.0, 1, Wind);
glPopMatrix();
end;
kosglSwapBuffers();
Rotation := Rotation + Speed;
TimeVal := TimeVal + 0.04;
end;
begin
TinyGL_initialization;
with GetScreenSize do
begin
WndWidth := Width div 3 * 2;
WndHeight := Height div 3 * 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'TinyGL Autumn Storm', $00FFFFFF,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
GLDraw;
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
ExitThread;
else
GLDraw;
end;
end.
@@ -0,0 +1,413 @@
program Perfect3DBalls;
uses
KolibriOS, TinyGL;
const
MAX_BALLS = 72;
GRAVITY = 0.015;
AIR = 0.99;
BOUNCE = -0.85;
type
TBall = record
Active: Boolean;
IsShard: Boolean;
X, Y, Z: Single;
VX, VY, VZ: Single;
Radius: Single;
Hue: Integer;
Darkness: Single;
Life: Single;
end;
var
WndLeft, WndTop, WndWidth, WndHeight: LongInt;
CTX: TKOSGLContext;
Balls: array[0..MAX_BALLS - 1] of TBall;
Angle: Single = 0.0;
BOX_X, BOX_Y, BOX_Z: Single;
i: Integer;
function Max(A, B: Extended): Extended; begin if A > B then Result := A else Result := B; end;
function Min(A, B: Extended): Extended; begin if A < B then Result := A else Result := B; end;
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
function Frac(N: Single): Single;
begin
Result := N - Trunc(N) ;
end;
procedure HSLtoRGB(H: Integer; S, L: Single; var R, G, B: Single);
var
C, X, M, R1, G1, B1: Single;
HPrime: Single;
begin
C := (1.0 - Abs(2.0 * L - 1.0)) * S;
HPrime := H / 60.0;
X := C * (1.0 - Abs(Frac(HPrime / 2.0) * 2.0 - 1.0));
M := L - C / 2.0;
if (HPrime >= 0) and (HPrime < 1) then begin R1 := C; G1 := X; B1 := 0; end
else if (HPrime >= 1) and (HPrime < 2) then begin R1 := X; G1 := C; B1 := 0; end
else if (HPrime >= 2) and (HPrime < 3) then begin R1 := 0; G1 := C; B1 := X; end
else if (HPrime >= 3) and (HPrime < 4) then begin R1 := 0; G1 := X; B1 := C; end
else if (HPrime >= 4) and (HPrime < 5) then begin R1 := X; G1 := 0; B1 := C; end
else begin R1 := C; G1 := 0; B1 := X; end;
R := R1 + M; G := G1 + M; B := B1 + M;
end;
procedure DrawSphere(Radius: Single);
var
l_i, l_j: Integer;
t_Segments: Integer;
lat0, z0, r0, lat1, z1, r1: Single;
lng, x, y: Single;
begin
t_Segments := 18;
for l_i := 0 to t_Segments - 1 do
begin
lat0 := PI * (-0.5 + l_i / t_Segments);
z0 := Sin(lat0);
r0 := Cos(lat0);
lat1 := PI * (-0.5 + (l_i + 1) / t_Segments);
z1 := Sin(lat1);
r1 := Cos(lat1);
glBegin(GL_QUAD_STRIP);
for l_j := 0 to t_Segments do
begin
lng := 2.0 * PI * l_j / t_Segments;
x := Cos(lng);
y := Sin(lng);
glNormal3f(x * r0, y * r0, z0);
glVertex3f(x * r0 * Radius, y * r0 * Radius, z0 * Radius);
glNormal3f(x * r1, y * r1, z1);
glVertex3f(x * r1 * Radius, y * r1 * Radius, z1 * Radius);
end;
glEnd();
end;
end;
procedure ResizeTopology(W, H: Integer);
begin
BOX_X := 5.0 * (W / H);
BOX_Y := 5.0;
BOX_Z := 5.0;
end;
function FindFreeBallIndex: Integer;
var
K: Integer;
begin
Result := -1;
for K := 0 to MAX_BALLS - 1 do
begin
if not Balls[K].Active then
begin
Result := K;
Exit;
end;
end;
end;
procedure SpawnBall(Index: Integer; IsShard: Boolean; ParentIndex: Integer);
begin
Balls[Index].Active := True;
Balls[Index].IsShard := IsShard;
Balls[Index].Darkness := 1.0;
if not IsShard then
begin
// ╧ю ты ■Єё  т ёрьюь тхЁїє (BOX_Y) ш ярфр■Є тэшч
Balls[Index].X := (Random * 100 / 100.0 - 0.5) * BOX_X * 1.6;
Balls[Index].Y := BOX_Y - 0.5 - (Random * 100 / 50.0);
Balls[Index].Z := (Random * 100 / 100.0 - 0.5) * BOX_Z * 1.6;
Balls[Index].VX := (Random * 100 / 100.0 - 0.5) * 0.4;
Balls[Index].VY := -(Random * 100 / 100.0) * 0.1; // ═ряЁртыхэшх тхъЄюЁр тэшч
Balls[Index].VZ := (Random * 100 / 100.0 - 0.5) * 0.4;
Balls[Index].Radius := 0.4 + (Random * 100 / 250.0);
Balls[Index].Hue := Trunc(Random * 360);
Balls[Index].Life := 1.0;
end
else
begin
Balls[Index].X := Balls[ParentIndex].X;
Balls[Index].Y := Balls[ParentIndex].Y;
Balls[Index].Z := Balls[ParentIndex].Z;
Balls[Index].Radius := Balls[ParentIndex].Radius * 0.35;
Balls[Index].Hue := Balls[ParentIndex].Hue;
Balls[Index].Life := 1.0;
end;
end;
procedure UpdatePhysics;
var
Idx, J, FreeIdx: Integer;
DX, DY, DZ, Dist, MinDist: Single;
NX, NY, NZ, Overlap: Single;
KX, KY, KZ, PFactor: Single;
XS, YS, ZS: Single;
begin
for Idx := 0 to MAX_BALLS - 1 do
begin
if not Balls[Idx].Active then Continue;
for J := Idx + 1 to MAX_BALLS - 1 do
begin
if not Balls[J].Active then Continue;
DX := Balls[J].X - Balls[Idx].X;
DY := Balls[J].Y - Balls[Idx].Y;
DZ := Balls[J].Z - Balls[Idx].Z;
Dist := Sqrt(DX * DX + DY * DY + DZ * DZ);
MinDist := Balls[Idx].Radius + Balls[J].Radius;
if Dist < MinDist then
begin
if Dist > 0.001 then
begin
NX := DX / Dist; NY := DY / Dist; NZ := DZ / Dist;
end
else
begin
NX := 0.1; NY := 0.0; NZ := 0.0;
end;
Overlap := MinDist - Dist;
Balls[Idx].X := Balls[Idx].X - NX * Overlap * 0.5;
Balls[Idx].Y := Balls[Idx].Y - NY * Overlap * 0.5;
Balls[Idx].Z := Balls[Idx].Z - NZ * Overlap * 0.5;
Balls[J].X := Balls[J].X + NX * Overlap * 0.5;
Balls[J].Y := Balls[J].Y + NY * Overlap * 0.5;
Balls[J].Z := Balls[J].Z + NZ * Overlap * 0.5;
KX := Balls[Idx].VX - Balls[J].VX;
KY := Balls[Idx].VY - Balls[J].VY;
KZ := Balls[Idx].VZ - Balls[J].VZ;
PFactor := 2.0 * (NX * KX + NY * KY + NZ * KZ) / 2.0 + 0.01;
Balls[Idx].VX := Balls[Idx].VX - PFactor * NX;
Balls[Idx].VY := Balls[Idx].VY - PFactor * NY;
Balls[Idx].VZ := Balls[Idx].VZ - PFactor * NZ;
Balls[J].VX := Balls[J].VX + PFactor * NX;
Balls[J].VY := Balls[J].VY + PFactor * NY;
Balls[J].VZ := Balls[J].VZ + PFactor * NZ;
end;
end;
end;
for Idx := 0 to MAX_BALLS - 1 do
begin
if not Balls[Idx].Active then Continue;
Balls[Idx].VY := Balls[Idx].VY - GRAVITY;
Balls[Idx].VX := Balls[Idx].VX * AIR;
Balls[Idx].VY := Balls[Idx].VY * AIR;
Balls[Idx].VZ := Balls[Idx].VZ * AIR;
Balls[Idx].X := Balls[Idx].X + Balls[Idx].VX;
Balls[Idx].Y := Balls[Idx].Y + Balls[Idx].VY;
Balls[Idx].Z := Balls[Idx].Z + Balls[Idx].VZ;
if Balls[Idx].IsShard then
begin
Balls[Idx].Life := Balls[Idx].Life - 0.015;
Balls[Idx].Darkness := Balls[Idx].Life;
if Balls[Idx].Y - Balls[Idx].Radius < -BOX_Y then
begin
Balls[Idx].Y := -BOX_Y + Balls[Idx].Radius; Balls[Idx].VY := Balls[Idx].VY * BOUNCE;
end;
if Balls[Idx].Y + Balls[Idx].Radius > BOX_Y then
begin
Balls[Idx].Y := BOX_Y - Balls[Idx].Radius; Balls[Idx].VY := Balls[Idx].VY * BOUNCE;
end;
if Balls[Idx].X - Balls[Idx].Radius < -BOX_X then
begin
Balls[Idx].X := -BOX_X + Balls[Idx].Radius; Balls[Idx].VX := Balls[Idx].VX * BOUNCE;
end;
if Balls[Idx].X + Balls[Idx].Radius > BOX_X then
begin
Balls[Idx].X := BOX_X - Balls[Idx].Radius; Balls[Idx].VX := Balls[Idx].VX * BOUNCE;
end;
if Balls[Idx].Z - Balls[Idx].Radius < -BOX_Z then
begin
Balls[Idx].Z := -BOX_Z + Balls[Idx].Radius; Balls[Idx].VZ := Balls[Idx].VZ * BOUNCE;
end;
if Balls[Idx].Z + Balls[Idx].Radius > BOX_Z then
begin
Balls[Idx].Z := BOX_Z - Balls[Idx].Radius; Balls[Idx].VZ := Balls[Idx].VZ * BOUNCE;
end;
if Balls[Idx].Life <= 0.0 then Balls[Idx].Active := False;
end
else
begin
// ╨рчЁє°хэшх сюы№°шї °рЁют яЁш ъюэЄръЄх ё ы■сющ шч 3D-уЁрэшЎ юъэр
if (Balls[Idx].Y - Balls[Idx].Radius < -BOX_Y) or
(Balls[Idx].Y + Balls[Idx].Radius > BOX_Y) or
(Abs(Balls[Idx].X) + Balls[Idx].Radius > BOX_X) or
(Abs(Balls[Idx].Z) + Balls[Idx].Radius > BOX_Z) then
begin
XS := -0.25;
while XS <= 0.25 do
begin
YS := -0.25;
while YS <= 0.25 do
begin
ZS := -0.25;
while ZS <= 0.25 do
begin
FreeIdx := FindFreeBallIndex;
if FreeIdx <> -1 then
begin
SpawnBall(FreeIdx, True, Idx);
Balls[FreeIdx].VX := Balls[Idx].VX * 0.4 + XS * (1.0 + Random * 50 / 100.0);
Balls[FreeIdx].VY := Balls[Idx].VY * BOUNCE + YS * (1.0 + Random * 50 / 100.0) + 0.15;
Balls[FreeIdx].VZ := Balls[Idx].VZ * 0.4 + ZS * (1.0 + Random * 50 / 100.0);
end;
ZS := ZS + 0.5;
end;
YS := YS + 0.5;
end;
XS := XS + 0.5;
end;
SpawnBall(Idx, False, 0);
end;
end;
end;
end;
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
CosA, SinA: Single;
LightPos: array[0..3] of GLfloat;
LightAmbient: array[0..3] of GLfloat;
LightDiffuse: array[0..3] of GLfloat;
MatAmbient: array[0..3] of GLfloat;
MatDiffuse: array[0..3] of GLfloat;
MatSpecular: array[0..3] of GLfloat;
R, G, B: Single;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
if not (ThreadInfo.Client.Height > 3) then Exit;
kosglMakeCurrent(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height, CTX);
glViewPort(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glClearColor(5/255, 6/255, 11/255, 0.0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
UpdatePhysics;
ResizeTopology(ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(45.0, ThreadInfo.Client.Width / ThreadInfo.Client.Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Angle := Angle + 0.003;
CosA := Cos(Angle); SinA := Sin(Angle);
glTranslatef(0.0, 0.0, -13.5);
// ═рёЄЁющър яючшЎшш ётхЄр (ёьх∙хэ ўєЄ№ т√°х фы  ъЁрёштюую сышър)
LightPos[0] := -8.0 * CosA - (-6.0) * SinA;
LightPos[1] := 15.0; // ═ряЁртыхэ ётхЁїє тэшч
LightPos[2] := -8.0 * SinA + (-6.0) * CosA;
LightPos[3] := 0.5;
LightAmbient[0] := 0.35; LightAmbient[1] := 0.35; LightAmbient[2] := 0.38; LightAmbient[3] := 0.5;
LightDiffuse[0] := 0.95; LightDiffuse[1] := 0.95; LightDiffuse[2] := 0.95; LightDiffuse[3] := 0.5;
glLightfv(GL_LIGHT0, GL_POSITION, @LightPos[0]);
glLightfv(GL_LIGHT0, GL_AMBIENT, @LightAmbient[0]);
glLightfv(GL_LIGHT0, GL_DIFFUSE, @LightDiffuse[0]);
MatSpecular[0] := 0.9; MatSpecular[1] := 0.9; MatSpecular[2] := 0.9; MatSpecular[3] := 0.5;
glMaterialfv(GL_FRONT, GL_SPECULAR, @MatSpecular[0]);
glMaterialf(GL_FRONT, GL_SHININESS, 64.0);
for i := 0 to MAX_BALLS - 1 do
begin
if not Balls[i].Active then Continue;
HSLtoRGB(Balls[i].Hue, 0.95, 0.55 * Balls[i].Darkness, R, G, B);
MatAmbient[0] := R * 0.6; MatAmbient[1] := G * 0.6; MatAmbient[2] := B * 0.6; MatAmbient[3] := 1.0;
MatDiffuse[0] := R; MatDiffuse[1] := G; MatDiffuse[2] := B; MatDiffuse[3] := 1.0;
glMaterialfv(GL_FRONT, GL_AMBIENT, @MatAmbient[0]);
glMaterialfv(GL_FRONT, GL_DIFFUSE, @MatDiffuse[0]);
glPushMatrix();
glTranslatef(Balls[i].X, Balls[i].Y, Balls[i].Z);
DrawSphere(Balls[i].Radius);
glPopMatrix();
end;
kosglSwapBuffers();
end;
begin
TinyGL_initialization;
Randomize;
with GetScreenSize do
begin
WndWidth := Width div 3 * 2;
WndHeight := Height div 3 * 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
ResizeTopology(WndWidth, WndHeight);
FillChar(Balls, SizeOf(Balls), #0);
for i := 0 to 24 do
begin
SpawnBall(i, False, 0);
// ╨рёяЁхфхы хь ЁртэюьхЁэю яю тёхщ т√ёюЄх ъюЁюсъш (юЄ -BOX_Y фю BOX_Y)
Balls[i].Y := -BOX_Y + 1.0 + (Random * 100 / 100.0) * (BOX_Y * 2.0 - 2.0);
end;
while True do
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'TinyGL Light 3D Balls', $00FFFFFF,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
GLDraw;
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
ExitThread;
else
GLDraw;
end;
end.
@@ -0,0 +1,22 @@
#SHS
rm Bublick_TinyGL.kex
rm CircleParticles_TinyGL.kex
rm DNAHelix3D_TinyGL.kex
rm FractalStormForest_TinyGL.kex
rm GravityShardBalls_TinyGL.kex
rm MengerSponge_TinyGL.kex
rm RubikRotate3D.kex
rm Sierpinski3D_TinyGL.kex
rm WaveMesh_TinyGL.kex
rm XDRUSH.kex
../xdpk.kex Bublick_TinyGL.pas
../xdpk.kex CircleParticles_TinyGL.pas
../xdpk.kex DNAHelix3D_TinyGL.pas
../xdpk.kex FractalStormForest_TinyGL.pas
../xdpk.kex GravityShardBalls_TinyGL.pas
../xdpk.kex MengerSponge_TinyGL.pas
../xdpk.kex RubikRotate3D.pas
../xdpk.kex Sierpinski3D_TinyGL.pas
../xdpk.kex WaveMesh_TinyGL.pas
../xdpk.kex XDRUSH.pas
exit
@@ -0,0 +1,207 @@
program MengerSpongeFractal;
uses
KolibriOS, TinyGL;
const
MAX_DEPTH = 2; { ├ыєсшэр ЇЁръЄрыр. ┬эшьрэшх: чэрўхэшх 3 чрЄюЁьючшЄ ёЄрЁ√щ яЁюЎхёёюЁ }
var
Rotation: GLFloat = 0;
Speed: GLFloat = 0.835;
ZTr: GLFloat = -5.0;
TimeVal: GLFloat = 0;
CTX: TKOSGLContext;
WndLeft, WndTop, WndWidth, WndHeight: LongInt;
IsLine: Boolean;
// ═рёЄЁющър яхЁёяхъЄшт√ ърьхЁ√
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
// ╬ЄЁшёютър срчютюую ъєср ЇЁръЄрыр ё яёхтфю-юётх∙хэшхь уЁрэхщ
procedure DrawSolidCube(Size: GLFloat);
var
S: GLFloat;
begin
S := Size * 0.5;
glBegin(GL_QUADS);
// ╧хЁхфэ   уЁрэ№ - ▀Ёър  сшЁ■чютр 
if not IsLine then
glColor3f(0.1, 0.7, 0.8)
else
glColor3f(0.5, 0.5, 0.5);
glVertex3f(-S, -S, S); glVertex3f( S, -S, S);
glVertex3f( S, S, S); glVertex3f(-S, S, S);
// ╟рфэ   уЁрэ№ - ╤шэ  
if not IsLine then
glColor3f(0.05, 0.4, 0.6)
else
glColor3f(0.5, 0.5, 0.5);
glVertex3f(-S, -S, -S); glVertex3f(-S, S, -S);
glVertex3f( S, S, -S); glVertex3f( S, -S, -S);
// ┬хЁїэ   уЁрэ№ - ╤тхЄыю-уюыєср 
if not IsLine then
glColor3f(0.2, 0.8, 1.0)
else
glColor3f(0.5, 0.5, 0.5);
glVertex3f(-S, S, -S); glVertex3f(-S, S, S);
glVertex3f( S, S, S); glVertex3f( S, S, -S);
// ═шцэ  уЁрэ№ - ╥хьэю-ёшэ  
if not IsLine then
glColor3f(0.02, 0.2, 0.4)
else
glColor3f(0.5, 0.5, 0.5);
glVertex3f(-S, -S, -S); glVertex3f( S, -S, -S);
glVertex3f( S, -S, S); glVertex3f(-S, -S, S);
// ╧Ёртр  уЁрэ№ }
if not IsLine then
glColor3f(0.08, 0.5, 0.7)
else
glColor3f(0.5, 0.5, 0.5);
glVertex3f( S, -S, -S); glVertex3f( S, S, -S);
glVertex3f( S, S, S); glVertex3f( S, -S, S);
// ╦хтр  уЁрэ№ }
if not IsLine then
glColor3f(0.06, 0.45, 0.65)
else
glColor3f(0.5, 0.5, 0.5);
glVertex3f(-S, -S, -S); glVertex3f(-S, -S, S);
glVertex3f(-S, S, S); glVertex3f(-S, S, -S);
glEnd();
end;
// ╨хъєЁёштэ√щ рыуюЁшЄь ухэхЁрЎшш ├єсъш ╠хэухЁр
procedure BuildSponge(X, Y, Z, Size: GLFloat; Depth: Integer);
var
NewSize: GLFloat;
dx, dy, dz: Integer;
Sum: Integer;
begin
// ┼ёыш фю°ыш фю яЁхфхыр ЁхъєЁёшш Ч Ёшёєхь ёяыю°эющ ъєсшъ т ¤Єшї ъююЁфшэрЄрї
if Depth = MAX_DEPTH then
begin
glPushMatrix();
glTranslatef(X, Y, Z);
DrawSolidCube(Size);
glPopMatrix();
end
else
begin
NewSize := Size / 3.0;
// ╧хЁхсшЁрхь ёхЄъє 3x3x3
for dx := -1 to 1 do
for dy := -1 to 1 do
for dz := -1 to 1 do
begin
// ┬√ўшёы хь ьрЄхьрЄшўхёъюх єёыютшх яєёЄюЄ√ фы  ├єсъш ╠хэухЁр
Sum := 0;
if dx = 0 then Inc(Sum);
if dy = 0 then Inc(Sum);
if dz = 0 then Inc(Sum);
// ┼ёыш сюыхх ўхь юфэр ъююЁфшэрЄр Ёртэр 0, ¤Єю ёътючэюх юЄтхЁёЄшх Ч яЁюяєёърхь хую
if Sum < 2 then
begin
BuildSponge(
X + dx * NewSize,
Y + dy * NewSize,
Z + dz * NewSize,
NewSize,
Depth + 1
);
end;
end;
end;
end;
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
Pulse: GLFloat;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
if ThreadInfo.Client.Height <= 3 then Exit;
kosglMakeCurrent(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height, CTX);
glViewPort(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glClearColor(0.03, 0.04, 0.06, 0.0); // ├ыєсюъшщ ъюёьшўхёъшщ Їюэ
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(45.0, ThreadInfo.Client.Width / ThreadInfo.Client.Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, ZTr);
// ┬Ёр∙рхь ЇЁръЄры яю фтєь юё ь фы  яюыэюЎхээюую 3D юсчюЁр
glRotatef(Rotation, 0.5, 1.0, 0.2);
// ┬√ўшёы хь Їшчшўхёъє■ яєы№ёрЎш■ ЁрчьхЁр юЄ тЁхьхэш
Pulse := 1.8 + Sin(TimeVal) * 0.25;
// ╟ряєёъ ухэхЁрЎшш ЇЁръЄрыр шч ЎхэЄЁр (0,0,0) ё фшэрьшўхёъшь ЁрчьхЁюь
IsLine := False;
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Ёшёєхь ё чрыштъющ
BuildSponge(0.0, 0.0, 0.0, Pulse, 0);
IsLine := True;
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Ёшёєхь ъюэЄєЁэ√х ышэшш
BuildSponge(0.0, 0.0, 0.0, Pulse, 0);
kosglSwapBuffers();
Rotation := Rotation + Speed;
TimeVal := TimeVal + 0.03;
end;
begin
TinyGL_initialization;
with GetScreenSize do
begin
WndWidth := Width div 3 * 2;
WndHeight := Height div 3 * 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'Menger Sponge 3D Fractal', $00FFFFFF,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
GLDraw;
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
ExitThread;
else
GLDraw;
end;
end.
@@ -0,0 +1,218 @@
program ParticleCubeFountain;
uses
KolibriOS, TinyGL;
const
MAX_PARTICLES = 100; // ьръёшьры№эюх ъюышўхёЄтю ъєсшъют
// ═└╤╥╨╬╔╩└ ╘╚╟╚╩╚
GRAVITY = 0.0066; // ╤шыр Є цхёЄш: ўхь ьхэ№°х, Єхь т√°х тчыхЄрхЄ ЇюэЄрэ
BOUNCE_FACTOR = 0.70; // ╩ю¤ЇЇшЎшхэЄ юЄёъюър: 0.70 ючэрўрхЄ ёюїЁрэхэшх 70% т√ёюЄ√ яЁ√цър
FLOOR_Y = -3.0; // ╙Ёютхэ№ яюыр, юЄ ъюЄюЁюую юЄёъръштр■Є ъєсшъш
type
TParticle = record
X, Y, Z: GLFloat;
VX, VY, VZ: GLFloat;
R, G, B: GLFloat;
Life: GLFloat;
end;
var
Particles: array[1..MAX_PARTICLES] of TParticle;
Rotation: GLFloat = 0;
Speed: GLFloat = 0.8;
ZTr: GLFloat = -15.0;
CTX: TKOSGLContext;
WndLeft, WndTop, WndWidth, WndHeight: LongInt;
// ═рёЄЁющър яхЁёяхъЄшт√ ърьхЁ√
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
procedure ResetParticle(Index: Integer);
begin
Particles[Index].X := 0.0;
Particles[Index].Y := -1.5;
Particles[Index].Z := 0.0;
Particles[Index].VX := ((Index mod 11) - 5) * 0.012;
Particles[Index].VY := 0.10 + (Index mod 7) * 0.012; // ═рўры№эр  ёъюЁюёЄ№ ттхЁї
Particles[Index].VZ := ((Index mod 13) - 6) * 0.012;
// ═рё√∙хээ√х ЎтхЄр (ёьхё№ ЇшюыхЄютюую, ёшэхую ш сшЁ■чютюую фы  ЁрчэююсЁрчш )
Particles[Index].R := 0.2 + (Index mod 4) * 0.2;
Particles[Index].G := 0.4 + (Index mod 6) * 0.1;
Particles[Index].B := 0.8 + (Index mod 3) * 0.1;
Particles[Index].Life := 1.0;
end;
procedure InitParticles;
var
I: Integer;
begin
for I := 1 to MAX_PARTICLES do
ResetParticle(I);
end;
procedure UpdatePhysics;
var
I: Integer;
begin
for I := 1 to MAX_PARTICLES do
begin
Particles[I].X := Particles[I].X + Particles[I].VX;
Particles[I].Y := Particles[I].Y + Particles[I].VY;
Particles[I].Z := Particles[I].Z + Particles[I].VZ;
// ╧Ёшьхэ хь эрёЄЁрштрхьє■ уЁртшЄрЎш■
Particles[I].VY := Particles[I].VY - GRAVITY;
// ╬Єёъюъ юЄ яюыр ё єўхЄюь эрёЄЁрштрхь√ї ярЁрьхЄЁют
if Particles[I].Y < FLOOR_Y then
begin
Particles[I].Y := FLOOR_Y;
Particles[I].VY := -Particles[I].VY * BOUNCE_FACTOR;
end;
Particles[I].Life := Particles[I].Life - 0.006;
if Particles[I].Life <= 0.0 then
ResetParticle(I);
end;
end;
// яЁюЎхфєЁр юЄЁшёютъш 3D-ъєср ё уЁрэ ьш
procedure DrawCube(R, G, B: GLFloat);
begin
glBegin(GL_QUADS);
// ╧хЁхфэ   уЁрэ№
glColor3f(R, G, B);
glVertex3f(-1.0, -1.0, 1.0); glVertex3f( 1.0, -1.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0);
// ╟рфэ   уЁрэ№
glColor3f(R * 0.8, G * 0.8, B * 0.8); // ╫єЄ№ Єхьэхх фы  юс·хьр
glVertex3f(-1.0, -1.0, -1.0); glVertex3f(-1.0, 1.0, -1.0);
glVertex3f( 1.0, 1.0, -1.0); glVertex3f( 1.0, -1.0, -1.0);
// ┬хЁїэ   уЁрэ№
glColor3f(R * 0.9, G * 0.9, B * 0.9);
glVertex3f(-1.0, 1.0, -1.0); glVertex3f(-1.0, 1.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0);
// ═шцэ   уЁрэ№
glColor3f(R * 0.6, G * 0.6, B * 0.6);
glVertex3f(-1.0, -1.0, -1.0); glVertex3f( 1.0, -1.0, -1.0);
glVertex3f( 1.0, -1.0, 1.0); glVertex3f(-1.0, -1.0, 1.0);
// ╧Ёртр  уЁрэ№
glColor3f(R * 0.85, G * 0.85, B * 0.85);
glVertex3f( 1.0, -1.0, -1.0); glVertex3f( 1.0, 1.0, -1.0);
glVertex3f( 1.0, 1.0, 1.0); glVertex3f( 1.0, -1.0, 1.0);
// ╦хтр  уЁрэ№
glColor3f(R * 0.75, G * 0.75, B * 0.75);
glVertex3f(-1.0, -1.0, -1.0); glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0); glVertex3f(-1.0, 1.0, -1.0);
glEnd();
end;
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
I: Integer;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
if ThreadInfo.Client.Height <= 3 then Exit;
kosglMakeCurrent(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height, CTX);
glViewPort(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glClearColor(0.05, 0.05, 0.1, 0.0); // ├ыєсюъшщ яюыєэюўэ√щ Їюэ
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(45.0, ThreadInfo.Client.Width / ThreadInfo.Client.Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, ZTr);
glRotatef(Rotation, 0.0, 1.0, 0.0); // ┬Ёр∙хэшх ёЎхэ√ яю юёш Y
// ╬ЄЁшёютър яыюёъюёЄш яюыр
glBegin(GL_QUADS);
glColor3f(0.25, 0.25, 0.45);
glVertex3f(-6.0, FLOOR_Y, 6.0);
glVertex3f( 6.0, FLOOR_Y, 6.0);
glVertex3f( 6.0, FLOOR_Y, -6.0);
glVertex3f(-6.0, FLOOR_Y, -6.0);
glEnd();
// ╓шъы юЄЁшёютъш 3D-ъєсшъют
for I := 1 to MAX_PARTICLES do
begin
glPushMatrix();
glTranslatef(Particles[I].X, Particles[I].Y, Particles[I].Z);
// ┬Ёр∙рхь ърцф√щ ъєсшъ тюъЁєу ётюхщ юёш фы  фшэрьшъш
glRotatef(Rotation * 2.5 + I, 0.4, 0.8, 0.2);
// ╠рё°ЄрсшЁєхь ъєс яЁюяюЁЎшюэры№эю хую тЁхьхэш цшчэш
glScalef(Particles[I].Life * 0.25, Particles[I].Life * 0.25, Particles[I].Life * 0.25);
// ┬√чют ърёЄюьэющ юЄЁшёютъш ухюьхЄЁшш
DrawCube(Particles[I].R, Particles[I].G, Particles[I].B);
glPopMatrix();
end;
kosglSwapBuffers();
UpdatePhysics;
Rotation := Rotation + Speed;
end;
begin
TinyGL_initialization;
InitParticles;
with GetScreenSize do
begin
WndWidth := Width div 3 * 2;
WndHeight := Height div 3 * 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'TinyGL 3D Cube Fountain', $00FFFFFF,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
GLDraw;
EndDraw;
end;
KEY_EVENT:
GetKey;
BUTTON_EVENT:
if GetButton.ID = 1 then
ExitThread;
else
GLDraw;
end;
end.
@@ -0,0 +1,226 @@
program RubikRotate3D;
uses
KolibriOS, TinyGL;
const
CUBE_DIST = 0.72; // ╨рёёЄю эшх ьхцфє ЎхэЄЁрьш ъєсшъют
type
TVertex3D = record
X, Y, Z: GLFloat;
end;
var
Rotation: GLFloat = 0;
CamSpeed: GLFloat = 0.5;
ZTr: GLFloat = -6.5;
TimeVal: GLFloat = 0;
// ╧рЁрьхЄЁ√ рэшьрЎшш ёыюхт
LayerAngle: GLFloat = 0;
ActiveAxis: Integer = 0; // 0 = X, 1 = Y, 2 = Z
ActiveLayer: Integer = -1; // -1 = ыхт√щ, 0 = ЎхэЄЁры№э√щ, 1 = яЁрт√щ
CTX: TKOSGLContext;
WndLeft, WndTop, WndWidth, WndHeight: LongInt;
// ═рёЄЁющър яхЁёяхъЄшт√ ърьхЁ√
procedure Perspective(fovY, Aspect, zNear, zFar: GLDouble);
var
fW, fH, fovYPI360: GLDouble;
M: array[0..15] of GLFloat;
begin
FillChar(M, SizeOf(M), #0);
fovYPI360 := fovY * PI / 360;
fH := Sin(fovYPI360) * zNear / Cos(fovYPI360);
fW := fH * Aspect;
M[0] := zNear / fW;
M[5] := zNear / fH;
M[10] := -(zFar + zNear) / (zFar - zNear);
M[11] := -1;
M[14] := -2 * zFar * zNear / (zFar - zNear);
glLoadMatrixf(@M[0]);
end;
// тЁр∙хэшх юфэющ 3D Єюўъш яю юё ь X, Y шыш Z
procedure RotatePoint(var Px, Py, Pz: GLFloat; Axis: Integer; AngleDegrees: GLFloat);
var
Rad, CosA, SinA, Tx, Ty, Tz: GLFloat;
begin
Rad := AngleDegrees * PI / 180.0;
CosA := Cos(Rad);
SinA := Sin(Rad);
Tx := Px; Ty := Py; Tz := Pz;
if Axis = 0 then { ┬юъЁєу X }
begin
Py := Ty * CosA - Tz * SinA;
Pz := Ty * SinA + Tz * CosA;
end
else if Axis = 1 then { ┬юъЁєу Y }
begin
Px := Tx * CosA + Tz * SinA;
Pz := -Tx * SinA + Tz * CosA;
end
else if Axis = 2 then { ┬юъЁєу Z }
begin
Px := Tx * CosA - Ty * SinA;
Py := Tx * SinA + Ty * CosA;
end;
end;
// ╬ЄЁшёютър ъєср ё  тэ√ь ЁрёўхЄюь 8 тхЁ°шэ
procedure DrawSubCube(S: GLFloat; GridX, GridY, GridZ: Integer; R, G, B: GLFloat);
var
Pts: array[0..7] of TVertex3D;
I: Integer;
IsLayerActive: Boolean;
begin
IsLayerActive := False;
if (ActiveAxis = 0) and (GridX = ActiveLayer) then IsLayerActive := True;
if (ActiveAxis = 1) and (GridY = ActiveLayer) then IsLayerActive := True;
if (ActiveAxis = 2) and (GridZ = ActiveLayer) then IsLayerActive := True;
// ╟рфрхь ыюъры№э√х ъююЁфшэрЄ√ ъєср
Pts[0].X := -S; Pts[0].Y := -S; Pts[0].Z := S;
Pts[1].X := S; Pts[1].Y := -S; Pts[1].Z := S;
Pts[2].X := S; Pts[2].Y := S; Pts[2].Z := S;
Pts[3].X := -S; Pts[3].Y := S; Pts[3].Z := S;
Pts[4].X := -S; Pts[4].Y := -S; Pts[4].Z := -S;
Pts[5].X := -S; Pts[5].Y := S; Pts[5].Z := -S;
Pts[6].X := S; Pts[6].Y := S; Pts[6].Z := -S;
Pts[7].X := S; Pts[7].Y := -S; Pts[7].Z := -S;
for I := 0 to 7 do
begin
// 1. ╤эрўрыр ёфтшурхь ¤ыхьхэЄ√ эр Ёрфшєё юЁсшЄ√
Pts[I].X := Pts[I].X + (GridX * CUBE_DIST);
Pts[I].Y := Pts[I].Y + (GridY * CUBE_DIST);
Pts[I].Z := Pts[I].Z + (GridZ * CUBE_DIST);
// 2. ┼ёыш ъєсшъ т ръЄштэюь ёыюх, тЁр∙рхь хую ёЄЁюую т ыюъры№э√ї юё ї
if IsLayerActive then
RotatePoint(Pts[I].X, Pts[I].Y, Pts[I].Z, ActiveAxis, LayerAngle);
end;
{ ┬√тюфшь 6 уЁрэхщ }
glBegin(GL_QUADS);
{ ╧хЁхфэ   }
glColor3f(R, G, B);
glVertex3f(Pts[0].X, Pts[0].Y, Pts[0].Z); glVertex3f(Pts[1].X, Pts[1].Y, Pts[1].Z);
glVertex3f(Pts[2].X, Pts[2].Y, Pts[2].Z); glVertex3f(Pts[3].X, Pts[3].Y, Pts[3].Z);
{ ╟рфэ   }
glColor3f(R * 0.5, G * 0.5, B * 0.5);
glVertex3f(Pts[4].X, Pts[4].Y, Pts[4].Z); glVertex3f(Pts[5].X, Pts[5].Y, Pts[5].Z);
glVertex3f(Pts[6].X, Pts[6].Y, Pts[6].Z); glVertex3f(Pts[7].X, Pts[7].Y, Pts[7].Z);
{ ┬хЁїэ   }
glColor3f(R * 0.9, G * 0.9, B * 0.9);
glVertex3f(Pts[5].X, Pts[5].Y, Pts[5].Z); glVertex3f(Pts[3].X, Pts[3].Y, Pts[3].Z);
glVertex3f(Pts[2].X, Pts[2].Y, Pts[2].Z); glVertex3f(Pts[6].X, Pts[6].Y, Pts[6].Z);
{ ═шцэ   }
glColor3f(R * 0.3, G * 0.3, B * 0.3);
glVertex3f(Pts[4].X, Pts[4].Y, Pts[4].Z); glVertex3f(Pts[7].X, Pts[7].Y, Pts[7].Z);
glVertex3f(Pts[1].X, Pts[1].Y, Pts[1].Z); glVertex3f(Pts[0].X, Pts[0].Y, Pts[0].Z);
{ ╧Ёртр  }
glColor3f(R * 0.8, G * 0.8, B * 0.8);
glVertex3f(Pts[7].X, Pts[7].Y, Pts[7].Z); glVertex3f(Pts[6].X, Pts[6].Y, Pts[6].Z);
glVertex3f(Pts[2].X, Pts[2].Y, Pts[2].Z); glVertex3f(Pts[1].X, Pts[1].Y, Pts[1].Z);
{ ╦хтр  }
glColor3f(R * 0.6, G * 0.6, B * 0.6);
glVertex3f(Pts[4].X, Pts[4].Y, Pts[4].Z); glVertex3f(Pts[0].X, Pts[0].Y, Pts[0].Z);
glVertex3f(Pts[3].X, Pts[3].Y, Pts[3].Z); glVertex3f(Pts[5].X, Pts[5].Y, Pts[5].Z);
glEnd();
end;
procedure UpdateRubikLogic;
begin
LayerAngle := LayerAngle + 3.0;
if LayerAngle >= 90.0 then
begin
LayerAngle := 0;
Inc(ActiveLayer);
if ActiveLayer > 1 then
begin
ActiveLayer := -1;
ActiveAxis := (ActiveAxis + 1) mod 3;
end;
end;
end;
procedure GLDraw;
var
ThreadInfo: TThreadInfo;
X, Y, Z: Integer;
R_Clr, G_Clr, B_Clr: GLFloat;
begin
GetThreadInfo($FFFFFFFF, ThreadInfo);
if ThreadInfo.Client.Height <= 3 then Exit;
kosglMakeCurrent(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height, CTX);
glViewPort(0, 0, ThreadInfo.Client.Width, ThreadInfo.Client.Height);
glClearColor(0.03, 0.03, 0.06, 0.0);
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
Perspective(45.0, ThreadInfo.Client.Width / ThreadInfo.Client.Height, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// ╠╚╨╬┬█┼ ╥╨└═╤╘╬╨╠└╓╚╚ (┬Ёр∙хэшх ърьхЁ√ тюъЁєу тёхщ ёЎхэ√)
glTranslatef(0.0, 0.0, ZTr);
glRotatef(25.0 + Rotation * 0.4, 1.0, 0.0, 0.0);
glRotatef(35.0 + Rotation, 0.0, 1.0, 0.0);
// ╤┴╬╨╩└ ╚ ╬╥╨╚╤╬┬╩└ ╤┼╥╩╚
for X := -1 to 1 do
for Y := -1 to 1 do
for Z := -1 to 1 do
begin
// ярышЄЁр эр ёшэєёрї юЄ тЁхьхэш
R_Clr := 0.7 + Sin(TimeVal + X * 0.5) * 0.3;
G_Clr := 0.7 + Cos(TimeVal * 0.8 + Y * 0.5) * 0.3;
B_Clr := 0.7 + Sin(TimeVal * 1.2 + Z * 0.5) * 0.3;
DrawSubCube(0.26, X, Y, Z, R_Clr, G_Clr, B_Clr);
end;
kosglSwapBuffers();
UpdateRubikLogic;
Rotation := Rotation + CamSpeed;
TimeVal := TimeVal + 0.03;
end;
begin
TinyGL_initialization;
with GetScreenSize do
begin
WndWidth := Width div 3 * 2;
WndHeight := Height div 3 * 2;
WndLeft := (Width - WndWidth) div 2;
WndTop := (Height - WndHeight) div 2;
end;
while True do
case WaitEventByTime(1) of
REDRAW_EVENT:
begin
BeginDraw;
DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, '3D Rubik Rotate', $00FFFFFF,
WS_SKINNED_SIZABLE + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
GLDraw;
EndDraw;
end;
KEY_EVENT: GetKey;
BUTTON_EVENT: if GetButton.ID = 1 then ExitThread;
else
GLDraw;
end;
end.
Loaded 100 of 314 files, more files were not shown because too many files have changed in this diff. Show more