type
// если с помощью шейдеров можно удалять тексели из текстуры, то для шейдеров не обязательно будет делать "вычитание спрайтов"
// с помощью "dataOut", значит и сохранять эти данные не обязательно.
pzTVRAMManager = record
// бланк видеопамяти в виде двух текстур для знакогенераторов.
// первые данные, указатель на полную видеостраницу (по умолчанию нулевая)
// вторые данные - именно две текстуры (видеопамять $0000-$0FFF и $1000-$1FFF).
VRAMTexture: array of array[0..1] of Cardinal;
// первое значение - номер в менеджере. Второе - банк видепамяти ($0000-$0FFF и $1000-$1FFF).
// Третье массив передаваемый в текстуру.
dataOut: array of array [0..1, 0..65535] of Cardinal; // 65535 * 4 не надо здесь менять на другое измерение, тут для цвета сделан размер.
// почему 65535, а не 49151 ? Делаю четвёртые данные для вычитания.
sprite: Cardinal;
Count: Cardinal;
end;
var
// менеджер копий видео-памяти, отображено в виде текстур (нужен если будет много сменяющихся бланков видеопамяти ).
managerVRAM: pzTVRAMManager;
// это данные как в текстурах, нужно это будет или нет? Например для отладки?
// vData: array [0..5, 0..4095] of Byte;
Texture0FrameCoord: array [0..1025] of zglTTextureCoord;
// пока для одного спрайта/тайла (3 текстуры).
Vertices: array [0..17] of zglGLESTVertex;
VertColor: array [0..17] of zglTColor;
...
// Для понимания. Данная функция может "сжирать" очень много процессорного времени. Она используется в играх, где происхоит постоянное перестроение
// данных изображения и происходит вызов почти на каждый кадр (а может и на каждый).
// Я сделал уже немало для ускорения работы данной функции, и думаю надо будет ещё сильнее ускорять её по возможности. Но проблема в том, что созданную
// текстуру ещё надо передать в память видеокарты, а это будет всегда "узким горлышком".
function texCreateCHRROM2(data1, data2: PByteArray; ID1, ID2: Cardinal): Boolean;
var
i, j2, j3, x, y, numData: pzInteger;
// Есть желание, тестируйте. В дальнейшем этот код удалю, оставляю только самый "перспективный".
procedure MovData1(data: PByteArray);
var
j: Integer;
n1, n2, nn1, nn2, XandY: Cardinal;
PmanVRAM: PCardinal;
begin
{ Not optimization }
PmanVRAM := @managerVRAM.dataOut[managerVRAM.Count - 1, numData];
// обнуляем данные
FillChar(PmanVRAM^, 65536 * 4, 0);
i := 4095;
y := 0;
while i >= 0 do // 4096
begin
x := 120;
j3 := 16; // 16 спрайтов в линии
while j3 > 0 do
begin
j2 := 8; // всего 8 линий в спрайте
while j2 > 0 do
begin
n1 := data^[i - 8]; // брать надо два байта (составляют одну линию).
n2 := data^[i];
// пробегаемся по данным в памяти
for j := 7 downto 0 do // одна линия спрайта.
begin
nn1 := ((n1 shr j) and 1);// * $FFFFFFFF;
nn2 := ((n2 shr j) and 1);
XandY := x + y * 128;
PmanVRAM := @managerVRAM.dataOut[managerVRAM.Count - 1, numData, XandY];
if nn1 = 1 then // удостоверится, что здесь именно байт браться будет.
begin
// в четвёртую текстуру дублирую запись, чтоб не делать лишних проверок.
PmanVRAM^ := $FFFFFFFF;
if nn2 = 1 then
begin
// третья текстура
inc(PmanVRAM, 16384);
PmanVRAM^ := $FFFFFFFF;
end
else begin
// первая текстура
inc(PmanVRAM, 49152);
PmanVRAM^ := $FFFFFFFF;
end;
end
else
if nn2 = 1 then
begin
// здесь продублировано.
PmanVRAM^ := $FFFFFFFF;
// вторая текстура
inc(PmanVRAM, 32768);
PmanVRAM^ := $FFFFFFFF;
end;
inc(x);
end;
x := x - 8;
inc(y); // переходим к следующей линии
dec(j2); // указываем что уменьшилось количество линий в спрайте.
dec(i); // смещаем
end;
dec(j3);
dec(y, 8); // вернуть на начальную линию
dec(x, 8); // сдвинуть икс на сделующий спрайт
dec(i, 8); // здесь смещение через спрайт (обработали уже два спрайта).
end;
y := y + 8; // если 16 спрайтов готово, то перейти на следующие спрайты
end;
end;
procedure MovData2(data: PByteArray);
var
j: Integer;
PmanVRAM: PCardinal;
n1, n2, nn1, nn2, XandY: Cardinal;
begin
{ First optimization }
//PmanVRAM := @managerVRAM.dataOut[managerVRAM.Count - 1, numData];
i := 4095;
y := 0;
while i >= 0 do // 4096
begin
x := 120;
j3 := 16; // 16 спрайтов в линии
while j3 > 0 do
begin
j2 := 8; // всего 8 линий в спрайте
while j2 > 0 do
begin
n1 := data^[i - 8]; // брать надо два байта (составляют одну линию).
n2 := data^[i];
// пробегаемся по данным в памяти
for j := 7 downto 0 do // одна линия спрайта.
begin
nn1 := -((n1 shr j) and 1);
nn2 := -((n2 shr j) and 1);
XandY := x + y * 128;
PmanVRAM := @managerVRAM.dataOut[managerVRAM.Count - 1, numData, XandY];
//XandY2 := 16384 + XandY1;
//XandY3 := 32768 + XandY1;
//XandY4 := 49152 + XandY1;
PmanVRAM^ := nn1 or nn2;
inc(PmanVRAM, 16384);
PmanVRAM^ := nn1 and nn2;
inc(PmanVRAM, 16384);
PmanVRAM^ := nn2;
inc(PmanVRAM, 16384);
PmanVRAM^ := nn1;
inc(x);
end;
x := x - 8;
inc(y); // переходим к следующей линии
dec(j2); // указываем что уменьшилось количество линий в спрайте.
dec(i); // смещаем
end;
dec(j3);
dec(y, 8); // вернуть на начальную линию
dec(x, 8); // сдвинуть икс на сделующий спрайт
dec(i, 8); // здесь смещение через спрайт (обработали уже два спрайта).
end;
y := y + 8; // если 16 спрайтов готово, то перейти на следующие спрайты
end;
end;
procedure MovData3(data: PByteArray);
var
j, z, j2, j3: Integer;
XandY: Cardinal;
m1, m2: array[0..7] of Cardinal;
PmanVRAM: PCardinal;
begin
{ Second optimization }
i := 4095;
y := 0;
while i >= 0 do // 4096
begin
x := 120;
for j3 := 15 downto 0 do // 16 спрайтов в линии
begin
for j2 := 7 downto 0 do // всего 8 линий в спрайте
begin
XandY := x + y * 128;
m1[0] := byte(data^[i - 8]); // брать надо два байта (составляют одну линию).
m2[0] := data^[i];
m1[1] := -((m1[0] shr 6) and 1); // заполняю массив данными
m2[1] := -((m2[0] shr 6) and 1);
m1[2] := -((m1[0] shr 5) and 1);
m2[2] := -((m2[0] shr 5) and 1);
m1[3] := -((m1[0] shr 4) and 1);
m2[3] := -((m2[0] shr 4) and 1);
m1[4] := -((m1[0] shr 3) and 1);
m2[4] := -((m2[0] shr 3) and 1);
m1[5] := -((m1[0] shr 2) and 1);
m2[5] := -((m2[0] shr 2) and 1);
m1[6] := -((m1[0] shr 1) and 1);
m2[6] := -((m2[0] shr 1) and 1);
m1[7] := -(m1[0] and 1);
m2[7] := -(m2[0] and 1);
m1[0] := -((m1[0] shr 7) and 1);
m2[0] := -((m2[0] shr 7) and 1);
PmanVRAM := @managerVRAM.dataOut[managerVRAM.Count - 1, numData, XandY];
// пробегаемся по данным в памяти
// четвёртая текстура
PmanVRAM^ := m1[0] or m2[0]; // первая линия 1
for z := 1 to 7 do
begin
inc(PmanVRAM);
PmanVRAM^ := m1[z] or m2[z]; // первая линия 2 3 4 5 6 7 8
end;
// третья текстура
inc(PmanVRAM, 16384 - 7);
PmanVRAM^ := m1[0] and m2[0]; // вторая линия
for z := 1 to 7 do
begin
inc(PmanVRAM);
PmanVRAM^ := m1[z] and m2[z]; // вторая линия
end;
// вторая текстура
inc(PmanVRAM, 16384 - 7);
PmanVRAM^ := m2[0]; // третья линия
for z := 1 to 7 do
begin
inc(PmanVRAM);
PmanVRAM^ := m2[z]; // третья линия
end;
// первая текстура
inc(PmanVRAM, 16384 - 7);
PmanVRAM^ := m1[0]; // четвёртая линия
for z := 1 to 7 do
begin
inc(PmanVRAM);
PmanVRAM^ := m1[z]; // четвёртая линия
end;
inc(y); // переходим к следующей линии
dec(i); // смещаем
end;
dec(y, 8); // вернуть на начальную линию
dec(x, 8); // сдвинуть икс на сделующий спрайт
dec(i, 8); // здесь смещение через спрайт (обработали уже два спрайта).
end;
y := y + 8; // если 16 спрайтов готово, то перейти на следующие спрайты
end;
end;
begin
Result := False;
numData := 0;
//для тестов
testTimeStart[0] := timer_GetTicks;
MovData1(data1);
testTimeEnd[0] := timer_GetTicks - testTimeStart[0];
testTimeRes[0] := (testTimeRes[0] + testTimeEnd[0]);
testTimeStart[1] := timer_GetTicks;
MovData2(data1);
testTimeEnd[1] := timer_GetTicks - testTimeStart[1];
testTimeRes[1] := (testTimeRes[1] + testTimeEnd[1]);
testTimeStart[2] := timer_GetTicks;
MovData3(data1);
testTimeEnd[2] := timer_GetTicks - testTimeStart[2];
testTimeRes[2] := (testTimeRes[2] + testTimeEnd[2]);
// MovData(data1);
tex_SetData(ID1, PByteArray(@managerVRAM.dataOut[managerVRAM.Count - 1, numData]), 0, 0, 128, 512);
numData := 1;
testTimeStart[0] := timer_GetTicks;
MovData1(data2);
testTimeEnd[0] := timer_GetTicks - testTimeStart[0];
testTimeRes[0] := (testTimeRes[0] + testTimeEnd[0]);
testTimeStart[1] := timer_GetTicks;
MovData2(data2);
testTimeEnd[1] := timer_GetTicks - testTimeStart[1];
testTimeRes[1] := (testTimeRes[1] + testTimeEnd[1]);
testTimeStart[2] := timer_GetTicks;
MovData3(data2);
testTimeEnd[2] := timer_GetTicks - testTimeStart[2];
testTimeRes[2] := (testTimeRes[2] + testTimeEnd[2]);
// MovData(data2);
tex_SetData(ID2, PByteArray(@managerVRAM.dataOut[managerVRAM.Count - 1, numData]), 0, 0, 128, 512);
Result := true;
end;