Заранее прошу сильно не смеяться. Вопроса как такового нет, а есть просьба посмотреть прогу … программа должна создавать конус с заданной высотой, радиусом и кол-вом граней. Только дело в том что создается что-то, но на конус это не похоже. Может кто чего подскажет… Код (Text): xor ebx,ebx ... fild [num]; кол-во граней fldpi ; число пи fadd st0,st0; пи+пи fdiv st0,st1; пи / кол-во граней fstp [alpha]; получился угол mov ecx,[num]; для цикла mov edi,model; указатель на массив push ebx;просто ноль, хотя нет, это начальный угол ( ну это для основания) .gen_loop: ; цикл ;запихнем точку (0,len,0) mov eax,ebx stosd mov eax,[len] stosd mov eax,ebx stosd fld dword [rad];радиус основания fld dword [esp];угол fsincos fmul st0,st2; радиус * косинус (координата по х) fstp dword [tmp] mov eax,[tmp] stosd fmul st0,st2; радиус * синус (координата по у) fstp dword [tmp] mov eax,[tmp] stosd mov eax,ebx; ноль (координата по z) stosd fadd dword [alpha]; увеличим угол fstp dword [esp]; loop .gen_loop
Ты не учитываешь, что fstp выталкивает st0 из стека fpu и смещает указатель вершины и то что было в st2 становится в st1 и т.д. Отсюда две ошибки: 1) fmul st0,st2; радиус*синус (координата по y) После fstp радиус лежит в st1, а не st2 ! 2) fadd dword [alpha] ;увеличим угол после двух fstp тут лежит радиус, а не угол (угол у тебя затирается при fsincos) Лучше сделать так: Код (Text): fld dword [rad] ;радиус fld dword [esp] ;угол ! если = 0, то проще fldz .gen_loop: ... ;запись точки (0,len,0) хотя не понятно, зачем они нужны ??? fld st0 ;копия угла fsincos ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус fmul st0,st3 ;x fstp dword [edi] fmul st0,st2 ;y fstp dword [edi+4] mov [edi+8],ebx ;z = 0 add edi,12 fadd dword [alpha] ;увеличиваем угол loop .gen_loop ;не забываем в конце очистить стек fpu fstp st0 fstp st0 ;у тебя тут еще в st0 остается [num] от первой загрузки ;поэтому либо нужен еще один fstp st0, либо замена fdiv st0,st1 на fdivrp st1,st0
Я попробовал то что мне предложил Leo и нашел одну ошибку... это конечно мой косяк, ошибка была в том что были перепутаны координаты Y и Z. Вот код с исправленными ошибками, проверенно все работает Код (Text): fild [num] ; кол-во граней fldpi ; число пи fadd st0,st0 ; пи+пи fdivrp st1,st0 ; пи / кол-во граней fstp [alpha] ; получился угол mov ecx,[num] ; для цикла ;inc ecx mov edi,models ; указатель на массив push ebx ;просто ноль, хотя нет, это начальный угол ( ну это для основания) fld dword [rad] ;радиус fldz ;начальный угол = 0 .gen_loop: ;запись точки (0,len,0) mov [edi],ebx ;x = 0 add edi,4 mov eax,[len] mov [edi],eax ;y = len add edi,4 mov [edi],ebx ;z = 0 add edi,4 ;запись точки (rad*cos(theta),0,rad*sin(theta)) fld st0 ;копия угла fsincos ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус fmul st0,st3 ;x fstp dword [edi] add edi,4 mov [edi],ebx ;y = 0 add edi,4 fmul st0,st2 ;z fstp dword [edi] add edi,4 fadd dword [alpha] ;увеличиваем угол ;запись точки (rad*cos(theta+alpha),0,rad*sin(theta+alpha)) fld st0 ;копия угла fsincos ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус fmul st0,st3 ;x fstp dword [edi] add edi,4 mov [edi],ebx ;y = 0 add edi,4 fmul st0,st2 ;z fstp dword [edi] add edi,4 loop .gen_loop ;не забываем в конце очистить стек fpu fstp st0 fstp st0 pop eax И еще, на последок, вот полный исходник (на Fasm'e) с экзешником -> _1522313718__OpenGL.rar
Всем приятного времени суток! Вот доделал программку, только хотелось бы ее оптимизировать. Может кто чего умного скажет... Вот код Код (Text): ;==================================================== ;-------------- СОЗДАНИЕ КОНУСА/ЦИЛИДРА------------- ;==================================================== fild [num] ; кол-во граней fldpi ; пи fadd st0,st0; 2*пи fdivrp st1,st0; fstp [alpha]; 2*пи/кол-во граней ;---------------------------------------------------- mov eax,[num]; кол-во боковых граней mov edi,model; указатель на объект ;---------------------------------------------------- fld dword [rad2] ;радиус fld dword [rad1] ;радиус fldz ;угол = 0 .gen_loop: ;========================== ;-- запись точки (0,0,0) -- push eax mov eax,ebx mov ecx,3 .zero: mov [edi],eax add edi,4 loop .zero ;========================================================= ; запись точки (r1*cos(theta),0,r1*sin(theta)) fld st0 ;копия угла fsincos ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус fmul st0,st3 ;x fstp dword [edi] add edi,4 mov [edi],eax ;y = 0 add edi,4 fmul st0,st2 ;z fstp dword [edi] add edi,4 ;========================================================= fadd dword [alpha] ;увеличиваем угол ;========================================================= ; запись точки (r1*cos(theta+alpha),0,r1*sin(theta+alpha)) fld st0 ;копия угла fsincos ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус fmul st0,st3 ;x fstp dword [edi] add edi,4 mov [edi],eax ;y = 0 add edi,4 fmul st0,st2 ;z fstp dword [edi] add edi,4 ;========================================================= mov eax,[rad2] test eax,eax jz .copy_1 ;--- копирование 2-х предыдущих точек --- mov ecx,6 .copy_: push dword [edi-24] pop dword [edi] add edi,4 loop .copy_ mov eax,[len] ;========================================================= ; запись точки (r2*cos(theta),len,r2*sin(theta)) fld st0 ;копия угла fsincos ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус fmul st0,st4 ;x fstp dword [edi] add edi,4 ;mov eax,[len] mov [edi],eax ;y = len add edi,4 fmul st0,st3 ;z fstp dword [edi] add edi,4 ;========================================================= ;--- копирование 2-х предыдущих точек --- push dword [edi-36] pop dword [edi] add edi,4 push dword [edi-36] pop dword [edi] add edi,4 push dword [edi-36] pop dword [edi] add edi,4 push dword [edi-24] pop dword [edi] add edi,4 push dword [edi-24] pop dword [edi] add edi,4 push dword [edi-24] pop dword [edi] add edi,4 fsub dword [alpha];уменьшим угол обратно ;========================================================= ; запись точки (r2*cos(theta+alpha),len,r2*sin(theta+alpha)) fld st0 ;копия угла fsincos ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус fmul st0,st4 ;x fstp dword [edi] add edi,4 ;mov eax,[len] mov [edi],eax ;y = len add edi,4 fmul st0,st3 ;z fstp dword [edi] add edi,4 ;========================================================= fadd dword [alpha] ;увеличиваем угол обатно еще раз ;jmp .no_copy ;========================================================= .copy_1: ;--- копирование 2-х предыдущих точек --- mov ecx,6 .copy: push dword [edi-24] pop dword [edi] add edi,4 loop .copy ;.no_copy: ;========================================================= ;--- запись точки (0,len,0) ---- mov [edi],ebx ;x = 0 add edi,4 mov eax,[len] mov [edi],eax ;y = len add edi,4 mov [edi],ebx ;z = 0 add edi,4 ;========================================================= pop eax dec eax jnz .gen_loop ;========================================================= ;не забываем в конце очистить стек fpu fstp st0 fstp st0 fstp st0 P.S. У меня есть свои соображения, только мозгов не хватает их реализовать (если хватало бы писал бы сразу туториал для DX/OGL). 1. Так вот, можно создать одну грань(т.е. 4 точки) и поворачивать вокруг центра на заранее вычесленный угол (вычислить sin/cos для alpha), а затем записывать это в буфер. 2. Если можно вытолкнуть из стека FPU регистр st2, то можно загнать часть кода в процедуру.
1) В каждом цикле изменяется максимум 2 точки, которые различаются только радиусом (при r2 > 0). Поэтому в цикле достаточно одного вычисления sin\cos, а остальные координаты можно просто копировать из предыдущих точек. 2) Для используемой точности dword (single precision) действительно можно заменить fsincos поворотом на фикс.угол alpha (4 умножения и 2 сложения) - будет намного быстрее. Можно делать поворот точки по первому радиусу r1, а для второго радиуса использовать умножение на заранее вычисленный коэффициент m=r2/r1. 3) Поскольку фигура симметричная, то достаточно вычислить точки для одного квадранта, а остальные - изменением знака X и Z (можно реализовать в целых числах как mov eax,mem1 + xor eax,80000000h + mov mem2,eax). Если попроще, то можно вычислять для 180 градусов (обратный порядок по X и изменение знака Z), если посложнее - для 45 градусов (с доп.заменой X и Z). 4) Для копирования памяти вместо push mem1 + pop mem2 нужно использовать mov r32,mem1 + mov mem2,r32; причем не нужно каждый раз изменять edi - лучше использовать смещение [edi+4], [edi+8] и т.д. и затем изменять edi на суммарный размер.
leo С пунктами 1 и 2 я полностью согласен (попробую реализовать и за одно проверю где код будет меньше), но вот п.3 я не понял. Если можешь поясни "на пальцах"
Поясняю на пальцах насчет симметрии. Самый простой вариант это расчитать половину точек, т.е. от 0 до 180 градусов (верхняя полуплоскость). Другая половина точек от 180 до 360 (нижняя полуплоскость) будет отличаться только знаками по координатам X и Z. Числа записаны в вещественном 4-байтном формате, где старший бит соответсвует знаку числа. Поэтому вместо того, чтобы грузить число в FPU и делать FCHS, можно просто сделать XOR старшего бита, т.е. поксорить с числом 80000000h (о нулевых значениях можно не беспокоиться, т.к. -0 для FPU такой же валидный ноль как и +0) Копирование будет выглядеть примерно так: Код (Text): mov ecx,[num] shr ecx,1 ;половина точек mov edx,12*3*2 ;размер одной грани для конуса cmp [rad2],0 jz .skip add edx,edx ;размер грани при rad2 > 0 .skip imul ecx,edx mov edi,model ;адрес уже просчитаных точек lea esi,[edi+ecx] ;адрес куда будем копировать @@: mov eax,[edi] xor eax,80000000h ;x=-x mov [esi],eax mov eax,[edi+4] mov [esi+4],eax mov eax,[edi+8] xor eax,80000000h ;z=-z mov [esi+8],eax add esi,12 add edi,12 sub ecx,12 jnz @B (при смене знаков х и z точка с углом t переходит в точку 180+t) Ес-но, размер кода несколько увеличивается. Поэтому это имеет смысл использовать, если нужно повысить скорость вычисления model. Это же кстати относится и к замене fsincos на поворот (умножения и сложения)