1

не буду приводить расчёты (потому что глупец). но кажется (я практически уверен что это факт) единственный способ это раскрытие циклов - абстрактно говоря. потому что мы тупо расписываем множество ветвлений, предполагая что можно заранее посчитать ветку поведения (скажем). у меня просто вопрос, так все делают: раскрывают на 16кб варианты отрисовки 8x8 спрайта со всеми смещениями. но если грубо посчитать в уме, не получается чтобы даже 8*8 вариантов помещалось в 16кб. а ведь ещё есть специфика экрана, с его тремя областями. вопрос в том: как это обычно делают?

2 (изменено: lenin1st, 15.09.2022 08:46:50)

[img=1323]https://www.shemale-porn-galls.com/galls/baileyjay/sex_hat_pic/3.jpg[/img]

3

лобовое решение: вывод на экран по линиям.
обходное решение - вывод "змейкой"

Ненависть- это подарок
защеканец gpv хорошо сосёт.

4 (изменено: lenin1st, 15.09.2022 15:00:36)

да это понятно всё. хотя что значит змейкой я не понял. я про то что есть алгоритм вывода в любую точку экрана, так. а если раскрыть циклы и знать первую точку (соответственно), можно очень навыигрывать сократив циклы. естественно все так делают, просто интересно насколько жёстко и что именно раскрывают. потому что так-то 64 варианта только начала спрайта есть, а ещё специфика экрана.

5

если выводить по линиям, то выходит побайтное копирование данных на экран, например (HL)->(DE). Нарисовав линию спрайта, нужно перейти вниз, по экрану, например

nbde    INC D:LD A,D:AND 7:RET NZ
        LD A,E:ADD A,#20:LD E,A:RET C
        LD A,D:SUB 8:LD D,A:RET

Казалось бы, удобнее  запомнить DE и сделать так

push de
;копирование линии
pop de
call nbde;переход на линию экрана

Трюк в том, что первая линия копируется, без сохранения регистра DE, а следующая линия копируется обратно
т.е. в первой линии будет
ld a,(hl)
ld (de),a
inc hl
inc e

а во второй

ld a,(hl)
ld (de),a
inc hl
dec e

Понятно, что нужно подготовить спрайт, чтобы шел другой порядок байтов.

Ненависть- это подарок
защеканец gpv хорошо сосёт.

6 (изменено: lenin1st, 15.09.2022 17:02:14)

щас пока не понял (уже накидался). но самое быстрое, как я понял, это заполнять экран через стек - это не наш путь, просто хотелось упомянуть. прочитаю завтра - осмыслю.

7

стек можно использовать, НО:
-число размер спрайта четное
-положение на экране одно и тоже
-нужно уместиться в 1 фрейм между прерываниями, иначе данные засрутся.

пример:

 ld (backsp+1),sp;сохранить стек
 ld sp, sprite ; стек указывает на данные спрайта
;развернутый цикл
 pop hl
 ld ($4000),hl
 pop hl
 ld ($4002),hl
 ... продолжить копирование одной линии
;вторая линия
 pop hl
 ld ($4100),hl
 pop hl
 ld ($4102),hl

backsp: ld sp,0;восстановить значение стека

можно по-другому, но с ограничениями.Например
pop bc
ld (hl),c
inc l
ld (hl),b
inc l

Ненависть- это подарок
защеканец gpv хорошо сосёт.

8 (изменено: lenin1st, 13.10.2022 15:43:14)

я немного ушёл головой и телом в плотнейшую лень. но держал в голове эту тему. вчера-позавчера начал ковырять. вот кстати даже ни разу не писал спрайты (не в частностях каких-то там), интересно поковыряться.

[b]Шыншыл[/b]
в nbde наверно не ret c и sub 8, а ret nc и add 8. и типа в среднем тогда (168*(4+4+7+11) + 21*(4+4+7+11+4+7+4+11) + 3*(4+4+7+11+4+7+4+11+4+7+4+10)) / 192 = 29.64~ ну да, я же что-то такое и писал уже. а почему-то в этот раз мне в голову залетела только таблица адресов.

ну а стек это понятно, чтобы экран двигать. то наверно не об этом.

ну а что поделать, вкину что высрал и пусть будет уже.

9

СПРАЙТ КСОРАМИ

оговорюсь об ограничениях (помимо того что это тупой ксор): немодифицирующийся код (код не меняется во время исполнения или непосредственно до); не выравненный по прерыванию и с правильным стеком - код всюду готов к прерыванию; код reentrant (при сохранении контекста на прерывании, можно вызвать этот же код пока он в процессе); формат хранения спрайта по линиям; отрисовка прямо на экран без теневого; без обработки ситуаций половинчатой отрисовки на краях экрана. по сути, всё для упрощения.

лобовая реализацию:

  #define SCREENPTR(HIGHBYTE, X, Y)                             \
    ((char*)(((HIGHBYTE) | ((Y) & 0xC0) >> 3 | (Y) & 0x07) << 8 \
             | (((Y) & 0x38) << 2 | (X) >> 3)))

  #define SPRITE(XBYTE, Y) (gl_ptr+(Y)*2+(XBYTE))

  void draw_sprite(int vpos_x, int vpos_y, int vsizex, int vsizey) {

    int x, y; char *ptr;

    for (y = 0; y != vsizey; y++) {

      for (x = 0; x != vsizex + (vpos_x&7?8:0); x += 8) {

        ptr = SCREENPTR(0x40, vpos_x+x, vpos_y+y);

        if (x < vsizex) {

          *ptr ^= *SPRITE(x/8, y) >> (vpos_x&7);
        }
        if (x >= 8 && (vpos_x&7)) {

          *ptr ^= *SPRITE((x-8)/8, y) << (8-(vpos_x&7));
        }
      }
    }

    return;
  }

первое что нужно раскрывать, это построчную отрисовку. потому что по горизонтали это тупо инкримент и потому что опционального сдвига нет (а мне почему-то кажется что это горячее место). получается 8 блоков отрисовки линий с разным сдвигом. ориентировка на форматы спрайтов 8x8, 16x16, 24x24, покрывает практически все случаи (из адекватных), так что я нацелюсь на них. но начнум с 16x16 и дальше будет видно (примерно умножив на 3) до какой глубины это можно довести.

отрисовка 16x16 спрайта, линии:

    .globl _draw_sprite16_line1
  _draw_sprite16_line1:
    pop bc
    pop hl
    pop de
    push de
    push hl
    push bc

    ;; 0 head
    ld  a,(de)
    srl a       ;; rrca; rrca; and a,#0x3f ...
    ld  b,(hl)
    xor a,b
    ld  (hl), a

    ;; 1 body
    ld  a,(de)
    rrca        ;; rrca; rrca; a,#0xc0 ...
    and a,#0x80 ;;
    ld  b,a

    inc l
    inc de

    ld  a,(de)
    srl a       ;; rrca; rrca; and a,#0x3f ...
    or  a,b
    ld  b,(hl)
    xor a,b
    ld  (hl), a

    ;; 2 tail
    ld  a,(de)
    rrca
    and a,#0x80 ;; rrca; rrca; and a,#0xc0 ...

    inc l

    ld  b,(hl)
    xor a,b
    ld  (hl), a

    ret

отрисовка 16x16 спрайта, верхний уровень:

  void draw_sprite2(int vpos_x, int vpos_y, int vsizex, int vsizey) {

  int y; char *ptr;

    if (vsizex != 16) {

      draw_sprite(vpos_x, vpos_y, vsizex, vsizey);
    }

    for (y = 0; y != vsizey; y++) {

      ptr = SCREENPTR(0x40, vpos_x, vpos_y+y);

      switch (vpos_x & 7) {
      case 0: draw_sprite16_line0(ptr, SPRITE(0, y)); break;
      case 1: draw_sprite16_line1(ptr, SPRITE(0, y)); break;
      case 2: draw_sprite16_line2(ptr, SPRITE(0, y)); break;
      case 3: draw_sprite16_line3(ptr, SPRITE(0, y)); break;
      case 4: draw_sprite16_line4(ptr, SPRITE(0, y)); break;
      case 5: draw_sprite16_line5(ptr, SPRITE(0, y)); break;
      case 6: draw_sprite16_line6(ptr, SPRITE(0, y)); break;
      case 7: draw_sprite16_line7(ptr, SPRITE(0, y)); break;
      }
    }

    return;
  }

(без пролога pop/push но с эпилогом ret, потому что пролог временный)
70+149+185+201+217+201+185+149 = 1357 t-states
11+28+38+42+46+42+38+28 = 273 bytes

сравнение с лобовой реализацией (прерываний на спрайт - отрисовка и очистка):
94/176 = 0.535~
377/176 = 2.142~
(1-2714/70908/(94/176) = 0.92~ процент времени в вышестоящем коде (прологе, в
C и библиотечном коде на прерываниях).
https://disk.yandex.com/d/p9yWzCoo2UNZtA
(тапка теста + частичный код (без библиотеки и сборщика))

10

[quote=lenin1st  88509]
в nbde наверно не ret c и sub 8, а ret nc и add 8. и типа в среднем тогда (168*(4+4+7+11) + 21*(4+4+7+11+4+7+4+11) + 3*(4+4+7+11+4+7+4+11+4+7+4+10)) / 192 = 29.64~ ну да, я же что-то такое и писал уже. а почему-то в этот раз мне в голову залетела только таблица адресов.

то, что есть. Для процедуры были другие изябретения.

Ненависть- это подарок
защеканец gpv хорошо сосёт.