Тема создана впрок, ну и для потрепаться на тему.
Надо было создать ещё восемь лет назад, когда начинал разработку, но всё казалось: вот ещё чуть доделаю, чтобы было что показать...
А потом подумал: да не, нунафиг. Линус вон ждал, ждал, а потом хряп! - и три ноль, типа живи-живи и ня топни? Вобщем, создам тему сейчас, чтобы потом, когда добьюсь величия, было что вспомнить, и не пришлось срочно строить домик, где прошло детство президента. Как-то так.
Предыдущие достижения:
http://chentrah.chebmaster.com/?what=log - трудное детство проЭкта.
http://www.gamedev.ru/code/forum/?id=184462 - 2014 год, разглагольствования (и рабочий пример с вертящимся кубиком) на тему Dynamic Resolution Rendering
https://gamedev.ru/projects/forum/?id=54656 - 2006 год, зарождение ключевого механизма СУБД движка.
Текущую версию для скачки см. на главной странице http://chentrah.chebmaster.com
P.S. Да, чуть не забыл. Декларируемые плюшки проекта (в окончательном виде):
P.P.S. Обновил список в ноябре 2019-го. Плохая новость: поддержки Windows 98 не будет.
* MPL 2.0 (имеет встроенную возможность использовать код под GPL/LGPL)
* всеядность (пойдёт на средней машине середины 2000-х) - нужна лишь OpenGL 2.1 или GL ES 2
* мощнейшая автонастройка рендера (сейчас уже вылезают траблы с перегревом ноута, т.к. оно выжимает из видеокарты всё даже на кубике, задирая рендерный буфер до 4k)
* официальная поддержка Raspberry Pi 2 B. Чиста для понтов.
* Эпическая масшьабируемость графики за счёт DRR, стохастической OIT и прочих продвинутых сверхлёгких технологий.
* десятки тысяч монстров одновременно за счёт сверхлёгкой ленивой физики. Причём, не на i9, а на той же Raspberry Pi.
* тысяча игроков против десяти тысяч монстров в мультиплеере, за счёт хитровывернутого варианта peer-to-peer (а точнее, сколько сеть потянет). Никаких бенчмарков или исследований я на эту тему пока не проводил.
Что пилю сейчас (З.Ы. было действительно на 2014-й):
Тест №18, фоновая загрузка из pk3 / zip архивов и рендеринг дофига md3 моделей из OpenArena.
Почему ещё не готово:
Яйца... танцору... А конкретно - выгребал старый говнокод и приводил месиво исходников в минимальный порядок, чтоб можно было хоть вносить изменения, не путаясь в коде аки тов. Лаокоонт.
За последние полгода удавлено более 10 леденящих кровь багов. Цитирую себя:
- Код: Выделить всё
1
The idea was to not use Free but Scrape, but with safeguard that Free is in fact redirected to Scrape.
It didn't work.
I *thought* I intercepted destructors in TManagedObject, redirecting them to Scrape. I was such an idiot. Should have intercepted FreeInstance instead of Destroy.
The fun: trashed memory due to blocks being released twice, as soon as I started using the garbage collector for real.
2
SetLength(ModuleCiMs, 1); ModuleCiMs[1]:= nil;
3
SetLength(ModuleCiMs, F.Count);
//this shit indexes beginning from 1, not 0!
//corrected to SetLength(ModuleCiMs, F.Count + 1);
4
var Res: TAOP;
...
TRes = packed record
Hash: TResourceHash;
...
PResourceHash(Res[i])^:=phash^;
...
with PRes(Res[i])^ do begin
...
PResourceHash(Res[i])^:=phash^;
...
inc(grri); if Resources[i]^.owner = CurrentOwner then begin //Wtf how did it even work?
5
CurrentOwner:= ActiveOwner; //where ActiveOwner was never set, remaining 0 (formerly the active module index)
6
Fas feeding get_caller_addr() with the result of a previous call to it, instead of the value returned by get_caller_frame(). It shouldn't have worked, but it was working. Somehow.
7
if Assigned(LockupGuard) then LockupGuard.Freeze; //after the LockupGuard is destroyed but the variable *not* unset :(
8
if EngineObject.Last is TThread then begin
(EngineObject.Last as TThread).Terminate;
if Mother^.State.DebugMode then AddLog(' waiting for the thread to terminate...');
(EngineObject.Last as TThread).WaitFor;
end;
EngineObject.Last.Free;
Should've either
A) declared the destructor as virtual (it _wasn't_)
TLockupGuard = class (TThread)
destructor Destroy;
//or
B) set the fucking FFreeOnTerminate to fucking false.
9
function WidePos(a, u: WideString): integer;
was parsing beyond the end of u
10
Was using SetUnhandledExceptionFilter() in each thread thinking it's a per-thread setting.
While MSDN states: Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.
Of course that fucked up the error processing, exceptions were popping during error processing, up to infinite error cycles and crash-to-desktop s.
Добавлено спустя 28 минут 47 секунд:
7 декабря
Затеянный на прошлой неделе кро-охотный поход в сторону, чтобы малость причесать оконный менеджер, вылился в
А) капитальный перетрях оконного менеджера, обработки сообщений окна и способа хранения позиции окна в конфиге (как вещественное число в долях экрана) и работающим переключением оконный/полноэкранный по F11.
что в итоге вылилось в
Б) организацию класса "фреймворк", в который напихал всю работу с окном, звуком и вводом, выдрав из основной помойки. Попотеть пришлось аки Франкенштейну, но! Теперь перевод с WinAPI (и X11 когда воскрешу-таки поддержку линукса), например, на GTK+ или SDL, будет гораздо проще, поскольку теперь всё это соединяется с основным телом движка через дюжину виртуальных методов и ооочень много полей глобальной переменной Mother
Как побочная плюшка, выделенный сервер делается из основной программы одной подстановкой в рантайме TWinApiFramework на TServerFramework . У последнего почти все методы - пустышки.
Возвращаясь после этого к А), вспомнил, что конь там по прежнему не валялся: окно иногда уплывает под панель задач, и плохо держит позицию при переключении с полноэкранного. Буду перелопачивать с SM_CXSCREEN на GetMonitorInfo