Пишу в этом разделе, т.к. графика (и моя трабла) очень близка именно к играм
Собственно что мне надо - есть какая-то картинка (спрайт или т.п.), скажем 200x210. Ее треба перемещать на экране по заданной траектории (не важно какой именно).
Проблема в том, что нужно устранить мерцание при движении спрайта (/фигуры)...
Что пробовал: 1. Стандартные фишки типа Getimage/putimage XOR'ом для рисования и стирания 2. Смена видеостраниц (двойная буферизация, тратата..) - что-то не очень-то помогает. К тому же мне хотелось бы использовать режим 640x480 - а это VGAHi и у него только 1 видеостраница. 3. Синхронизация с обратным ходом лучей - нечто мистическое (думается для CRT моников самое то), но у меня LCD и ускорения или устранения мерцания таким вот образом я не наблюдаю 4. Нашел в инете статейки со вставками на асме и т.п. - асм юзать не хочется, т.к. в нем ничерта не понимаю Из более-менее схожего - есть обращение к видеопамяти напрямую - $A000:$0000 - начиная отсюда и далее.
Дык вот, внимание, сам вопрос (барабанная дробь):
Как в этом самом режиме VGAHi 640x480@16 устроена эта самая видеопамять? Т.е. как она представлена в памяти? 16 цветов - это типа полбайта на пиксель чтоли?
В общем хелп ми
P.S.: Можно ли в каких-нибудь настройках форума сделать так, чтобы все сообщения в теме выводились полностью, а не по одному и с деревом снизу - как-то непривычно...
1. При использовании буфера в памяти, мерцания не видно даже без обратного хода луча. А с ним не должно быть заметно и при переключении видео страниц. Покажи код, иначе не разберёмся в чём твоя трабла. 2. Ага, 4 бита на пиксел. Используй побитовые сдвиги и логические операции. 3. Насчёт твоего PS, не знаю. Этот форум даже в текстовой версии выводит все сообщения сразу.
P.S.: Можно ли в каких-нибудь настройках форума сделать так, чтобы все сообщения в теме выводились полностью, а не по одному и с деревом снизу - как-то непривычно...
Кнопка "Опции" в самом верху темы (первое сообщение, справа от названия)... Нажимаешь, выбираешь "Стандартный"...
Как в этом самом режиме VGAHi 640x480@16 устроена эта самая видеопамять? Т.е. как она представлена в памяти? 16 цветов - это типа полбайта на пиксель чтоли?
С одной стороны да, по 4 бита. Но если просто писать и читать из памяти - изображение получится черно-белое. Если мне не изменяет память (а это легко проверить при желании), запись одного байта отображает 8 точек. Для того чтобы получить цвет нужно через порты видеокарты менять текущий слой для отображения (их как раз 4). Т.е. выбираешь по очереди слои и пишешь по одному и тому же адресу данные.. Немного сложновато, но зато можно получить интересный эффект получпрозрачного наложения друг на друга разных ихображений Т.е. получается такой пирог из слоев, например при записи: слой данные 1: 10101010 2: 00000001 3: 10000001 4: 01010101
1. При использовании буфера в памяти, мерцания не видно даже без обратного хода луча. А с ним не должно быть заметно и при переключении видео страниц. Покажи код, иначе не разберёмся в чём твоя трабла. 2. Ага, 4 бита на пиксел. Используй побитовые сдвиги и логические операции. 3. Насчёт твоего PS, не знаю. Этот форум даже в текстовой версии выводит все сообщения сразу.
Вот полный листинг проги. Используется режим VGAMed (т.к. нужно 2 страницы, а в Hi - только одна). Однако ужасно мерцает...
2. - А как именно все это дело в памяти представлено? Я пробовал выводить через mem[$A000:$0000]:=byte1; Выводит в точку с координатами 0,0 (если byte=128=bin'10000000') - а вот что с цветом и как с остальными - не особо понятно... Как там представлено все в VGAHi?
program RO_i_OI_lab02_ver05; uses crt,graph; var cl,bcl:integer; xbase,ybase:integer; P: Pointer; Size: Word; vis,act:boolean; c:char; oldx,oldy,x,y,alf1,alf2,delt1,delt2:real; fl,t:integer; {--------------------------------------------} procedure InitGr; var grDriver: Integer; grMode: Integer; ErrCode: Integer; begin grDriver := Detect; InitGraph(grDriver, grMode,''); ErrCode := GraphResult; if not (ErrCode = grOk) then begin writeln('Graphics error:', GraphErrorMsg(ErrCode)); end; end;
procedure CloseGr; begin CloseGraph; end; {--------------------------------------------} procedure drawLine(xx1,yy1,xx2,yy2:integer); var k,b:real; x1,y1,x2,y2:real; Xmax,Xmin,Ymax,Ymin:real; xr,yr,delta:real; dl:integer; {delay} begin
if x1>=x2 then begin Xmax:=x1; Xmin:=x2; end {switch X, x1<x2, x1=Xmin, x2=Xmax} else begin Xmax:=x2; Xmin:=x1; end; if y1>=y2 then begin Ymax:=y1; Ymin:=y2; end {switch Y, y1<y2, y1=Ymin, y2=Ymax} else begin Ymax:=y2; Ymin:=y1; end;
if x1<>x2 then begin {y=k*x+b, Xmin<=x<=Xmax, Ymin<=y<=Ymax} k:=(y2-y1)/(x2-x1); b:=y1-k*x1;
if y1=y2 then begin {line->point} putpixel(xx1,yy1,cl); {x1=x2, y1=y2} end else begin {vertical line} delta:=1; xr:=x1; {x1=x2} yr:=Ymin; repeat putpixel(trunc(xr),trunc(yr),cl); yr:=yr+delta; delay(dl); until (yr>Ymax); end; end; end; {--------------------------------------------} procedure drawCircle(xx,yy,rr:integer); var x,y,r:real; alpha,delta:real; dvaPi:real; dl:integer; begin dl:=0; {integer->real} r:=rr;
dvaPi:=2*pi; delta:=0.01; {step of angle} alpha:=0;
repeat x:=r*cos(alpha); y:=r*sin(alpha); putpixel(trunc(x)+xx,trunc(y)+yy,cl); alpha:=alpha+delta; delay(dl); until alpha>dvaPi;
end; {--------------------------------------------} procedure drawEllipse(xx,yy,xxr,yyr:integer); var x,y,xr,yr:real; alpha,delta:real; dvaPi:real; dl:integer; begin dl:=0; {integer->real} xr:=xxr; yr:=yyr;
dvaPi:=2*pi; delta:=0.01; {step of angle} alpha:=0;
repeat x:=xr*cos(alpha); y:=yr*sin(alpha); putpixel(trunc(x)+xx,trunc(y)+yy,cl); alpha:=alpha+delta; delay(dl); until alpha>dvaPi;
end;
{--------------------------------------------} procedure drawRectangle(x1,y1,x2,y2:integer); begin drawline(x1,y1,x2,y1); drawline(x2,y1,x2,y2); drawline(x2,y2,x1,y2); drawline(x1,y2,x1,y1); end;
{--------------------------------------------} procedure drawman(xbase,ybase:integer); begin drawrectangle(xbase-20,ybase-25,xbase+20,ybase+25); {telo} drawcircle(xbase,ybase-45,12); {golova}
end; {--------------------------------------------} procedure switchvisual(var f:boolean); begin if f then begin setvisualpage(1); f:=false; end else begin setvisualpage(0); f:=true; end; end;
procedure switchactive(var f:boolean); begin if f then begin setactivepage(1); f:=false; end else begin setactivepage(0); f:=true; end; end;
{--------------------------------------------} procedure WaitVerticalRetrace; begin while (port[$3da] and 8)=0 do; end;
С одной стороны да, по 4 бита. Но если просто писать и читать из памяти - изображение получится черно-белое. Если мне не изменяет память (а это легко проверить при желании), запись одного байта отображает 8 точек. Для того чтобы получить цвет нужно через порты видеокарты менять текущий слой для отображения (их как раз 4). Т.е. выбираешь по очереди слои и пишешь по одному и тому же адресу данные.. Немного сложновато, но зато можно получить интересный эффект получпрозрачного наложения друг на друга разных ихображений Т.е. получается такой пирог из слоев, например при записи: слой данные 1: 10101010 2: 00000001 3: 10000001 4: 01010101
поучится полоска с цветами А 1 8 1 8 1 7..
То что чернобелое получается - это я заметил И именно поэтому не понял.... Можешь подробнее объяснить про слои... и запись в них.... лучше если на пальцах
Как читать пиксел - не знаю, но вот про запись: Port[$03C4] := 2; после этого можно менять битовые плоскости для вывода Port[$03C5] := A; Число A от 0 до 15. Пусть оно в двоичной системе счисления имеет вид 1001. Это означает, что после этого момента запись будет идти в нулевую и третью плоскости - соостветственно ненулевым битам числа A. По умолчанию запись идёт во все 4 плоскости. Могу предложить свой модуль. Буферный вывод без асма - это ничего хорошего, потому что массовые копирования областей памяти с помощью процедуры Move делаютcя похоже командой movsb, которая вдвое медленней команды movsw. Советую обратить внимание на типы TLayer и TScreenBuffer и на процедуры InitGraph, CloseGraph, ClearBuffer, OutBuffer (она самая важная - имеет один параметр - количество приёмов, в которое будет идти вывод. Слишком много - нельзя, так как будет тормозить, слишком мало - нельзя, так как плоскости будут выводиться по очереди и в те милисекунды между выводом плоскостей картинка имеет странные цвета, и при малых значениях параметра глаз это видит). Ну и на процедуру PutPixel - вывод пиксела в буфер. Остальное - по ходу дела наслоилось. Минусы - буфер жрёт немеренно памяти, поэтому либо вообще программу нельзя будет из Паскаля запускать (только екзешник), либо указать компилятору (Options -> Memory Sizes -> StackSize поменять допустим на 16000), чтобы он для стека поменьше памяти забрал (но учтите, что слишком маленький стек может заглючить программу). И ещё вывод буфера - операция долгая (хотя все равно втрое быстрее, чем ClearViewPort)