From e643356bbcd3bf5cd111b029799a2a4aa4710707 Mon Sep 17 00:00:00 2001 From: IgorA Date: Fri, 2 Sep 2016 09:26:04 +0000 Subject: [PATCH] info3ds_u: add new mode to view material colors git-svn-id: svn://kolibrios.org@6509 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/info3ds/info3ds_u.asm | 58 ++--- programs/develop/info3ds/info_o3d.inc | 303 ++++++++++++++++++------- programs/develop/info3ds/toolbar.png | Bin 2815 -> 3541 bytes 3 files changed, 254 insertions(+), 107 deletions(-) diff --git a/programs/develop/info3ds/info3ds_u.asm b/programs/develop/info3ds/info3ds_u.asm index 336e84e113..4d95d5db81 100644 --- a/programs/develop/info3ds/info3ds_u.asm +++ b/programs/develop/info3ds/info3ds_u.asm @@ -31,6 +31,12 @@ ID_ICON_POINT_SEL equ 9 FILE_ERROR_CHUNK_SIZE equ -3 ;ошибка в размере блока +size_one_list equ 42+sizeof.obj_3d +list_offs_chunk_del equ 8 ;может ли блок удалятся +list_offs_chunk_lev equ 9 ;уровень блока (прописан в данные узла) +list_offs_p_data equ 10 ;указатель на подпись блока +list_offs_obj3d equ 14 ;указатель на структуру данных для 3d объекта +list_offs_text equ 14+sizeof.obj_3d ;сдвиг начала текста в листе include 'info_o3d.inc' align 4 @@ -57,12 +63,6 @@ file_3ds: ; .size: dd 0 ;+4 размер блока (для 1-го параметра = размер файла 3ds) rb 8*MAX_FILE_LEVEL -size_one_list equ 42+sizeof.obj_3d -list_offs_chunk_del equ 8 ;может ли блок удалятся -list_offs_chunk_lev equ 9 ;уровень блока (прописан в данные узла) -list_offs_p_data equ 10 ;указатель на подпись блока -list_offs_obj3d equ 14 ;указатель на структуру данных для 3d объекта -list_offs_text equ 14+sizeof.obj_3d ;сдвиг начала текста в листе buffer rb size_one_list ;буфер для добавления структур в список tree1 txt_3ds_symb db 0,0 @@ -113,11 +113,11 @@ start: stdcall [ksubmenu_add], [main_menu_view], eax stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Veiw_Faces_Fill, 7 stdcall [ksubmenu_add], [main_menu_view], eax - stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Veiw_Light, 8 + stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Veiw_Light, 9 stdcall [ksubmenu_add], [main_menu_view], eax stdcall [kmenuitem_new], KMENUITEM_SEPARATOR, 0, 0 stdcall [ksubmenu_add], [main_menu_view], eax - stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Veiw_Reset, 9 + stdcall [kmenuitem_new], KMENUITEM_NORMAL, sz_main_menu_Veiw_Reset, 10 stdcall [ksubmenu_add], [main_menu_view], eax stdcall [kmenuitem_new], KMENUITEM_SUBMENU, sz_main_menu_View, [main_menu_view] stdcall [ksubmenu_add], [main_menu], eax @@ -395,7 +395,7 @@ timer_funct: stdcall draw_material,edi jmp .end_f .ini_mblo: - stdcall mat_init,edi ;попытка настроить данные материала + stdcall mat_init,edi,eax ;попытка настроить данные материала cmp dword[edi+offs_mat_name],0 je .end_f stdcall draw_material,edi @@ -438,25 +438,28 @@ pushad mov esi,[sc.work_button] mcall SF_DEFINE_BUTTON,(5 shl 16)+20,(24 shl 16)+20,0x40000003 mcall ,(30 shl 16)+20,,0x40000004 ;open - mcall ,(3d_wnd_l shl 16)+20,,0x40000005 ;вершины вкл./выкл. - mcall ,((3d_wnd_l+25) shl 16)+20,,0x40000006 ;грани вкл./выкл. - mcall ,((3d_wnd_l+50) shl 16)+20,,0x40000007 ;заливка граней вкл./выкл. - mcall ,((3d_wnd_l+75) shl 16)+20,,0x40000008 ;свет вкл./выкл. - mcall ,((3d_wnd_l+100) shl 16)+20,,0x40000009 ;сброс + mcall ,(3d_wnd_l shl 16)+20,,0x40000005 ;вершины вкл. + mcall ,((3d_wnd_l+25) shl 16)+20,,0x40000006 ;каркасные грани вкл. + mcall ,((3d_wnd_l+50) shl 16)+20,,0x40000007 ;заливка граней вкл. + mcall ,((3d_wnd_l+75) shl 16)+20,,0x40000008 ;грани по материалам вкл. + mcall ,((3d_wnd_l+100) shl 16)+20,,0x40000009 ;свет вкл./выкл. + mcall ,((3d_wnd_l+125) shl 16)+20,,0x4000000a ;сброс mcall SF_PUT_IMAGE,[image_data_toolbar],(21 shl 16)+21,(5 shl 16)+24 ;new add ebx,IMAGE_TOOLBAR_ICON_SIZE mcall ,,,(30 shl 16)+24 ;open add ebx,IMAGE_TOOLBAR_ICON_SIZE*6 - mcall ,,,((3d_wnd_l) shl 16)+24 ;вершины вкл./выкл. + mcall ,,,((3d_wnd_l) shl 16)+24 ;вершины вкл. add ebx,IMAGE_TOOLBAR_ICON_SIZE - mcall ,,,((3d_wnd_l+25) shl 16)+24 ;грани вкл./выкл. + mcall ,,,((3d_wnd_l+25) shl 16)+24 ;каркасные грани вкл. add ebx,IMAGE_TOOLBAR_ICON_SIZE - mcall ,,,((3d_wnd_l+50) shl 16)+24 ;заливка граней вкл./выкл. + mcall ,,,((3d_wnd_l+50) shl 16)+24 ;заливка граней вкл. add ebx,IMAGE_TOOLBAR_ICON_SIZE - mcall ,,,((3d_wnd_l+75) shl 16)+24 ;свет вкл./выкл. + mcall ,,,((3d_wnd_l+100) shl 16)+24 ;свет вкл./выкл. add ebx,IMAGE_TOOLBAR_ICON_SIZE - mcall ,,,((3d_wnd_l+100) shl 16)+24 ;сброс + mcall ,,,((3d_wnd_l+125) shl 16)+24 ;сброс + add ebx,IMAGE_TOOLBAR_ICON_SIZE + mcall ,,,((3d_wnd_l+75) shl 16)+24 ;грани по материалам вкл. mov dword[w_scr_t1.all_redraw],1 stdcall [tl_draw], tree1 @@ -561,10 +564,15 @@ button: @@: cmp ah,8 jne @f - call mnu_light_on_off + call mnu_faces_mat jmp still @@: cmp ah,9 + jne @f + call mnu_light_on_off + jmp still + @@: + cmp ah,10 jne @f call mnu_reset_settings jmp still @@ -1397,9 +1405,9 @@ white_light dd 0.8, 0.8, 0.8, 1.0 ; lmodel_ambient dd 0.3, 0.3, 0.3, 1.0 ; Параметры фонового освещения if lang eq ru -capt db 'info 3ds [user] версия 18.02.16',0 ;подпись окна +capt db 'info 3ds [user] версия 02.09.16',0 ;подпись окна else -capt db 'info 3ds [user] version 18.02.16',0 ;window caption +capt db 'info 3ds [user] version 02.09.16',0 ;window caption end if align 16 @@ -1417,13 +1425,11 @@ i_end: color_vert rd 1 color_face rd 1 color_select rd 1 - rb 2048 align 16 -thread_coords: - rb 2048 + rb 4096 stacktop: sys_path rb 2048 - file_name rb 4096 + file_name rb 4096 plugin_path rb 4096 openfile_path rb 4096 filename_area rb 256 diff --git a/programs/develop/info3ds/info_o3d.inc b/programs/develop/info3ds/info_o3d.inc index 6f15d8e453..ab37d32844 100644 --- a/programs/develop/info3ds/info_o3d.inc +++ b/programs/develop/info3ds/info_o3d.inc @@ -25,6 +25,7 @@ struct obj_3d z_min dd ? z_centr dd ? z_scale dd ? + mat1_data dd ? ;данные 1-го материала в объекте ends offs_obj_poi_data equ 0 ;указатель на координаты вершин @@ -47,6 +48,7 @@ offs_obj_z_max equ 64 offs_obj_z_min equ 68 offs_obj_z_centr equ 72 offs_obj_z_scale equ 76 +offs_obj_mat1_data equ 80 struct material name dd ? @@ -64,6 +66,7 @@ bit_vertexes equ 0 bit_faces equ 1 bit_faces_fill equ 2 bit_light equ 3 +bit_faces_mat equ 4 ini_name db 'info3ds.ini',0 ini_sec_w3d db 'Window 3d',0 @@ -118,6 +121,7 @@ proc obj_clear_param uses edi, o_data:dword mov dword[edi+offs_obj_tri_count],0 mov dword[edi+offs_obj_normals_tri_count],0 mov dword[edi+offs_obj_normals_poi_count],0 + mov dword[edi+offs_obj_mat1_data],0 cmp dword[edi+offs_obj_normals_tri_data],0 je @f stdcall mem.Free,[edi+offs_obj_normals_tri_data] @@ -526,6 +530,13 @@ proc obj_init, o_data:dword mov [edi+offs_obj_tri_count],edx add esi,8 ;2+4+2 (chunk+size+count) mov [edi+offs_obj_tri_data],esi + + ;поиск материалов граней + shl edx,3 + add esi,edx + cmp word[esi],CHUNK_FACEMAT + jne .end_points + mov [edi+offs_obj_mat1_data],esi .end_points: stdcall obj_set_sizes, edi @@ -539,8 +550,11 @@ end if endp ;настройка материала +;input: +; m_data - указатель на заполняемую структуру с материалом +; f_data - указательна на блок CHUNK_MATERIAL из файла 3ds align 4 -proc mat_init, m_data:dword +proc mat_init, m_data:dword, f_data:dword pushad mov edi,[m_data] @@ -550,86 +564,82 @@ proc mat_init, m_data:dword mov dword[edi+offs_mat_col_diffuse],0 mov dword[edi+offs_mat_col_specular],0 - stdcall [tl_node_get_data],tree1 xor edx,edx - cmp eax,0 - je .no_material - mov ebx,[eax] ;получаем значение сдвига выбранного блока - add ebx,[open_file_data] - xor ecx,ecx - cmp word[ebx],CHUNK_MATERIAL - jne .no_material - mov ecx,ebx - add ecx,dword[ecx+2] ;граница блока - add ebx,6 - cmp word[ebx],CHUNK_MATNAME - jne .no_material - ;*** (0) *** - mov esi,ebx - add ebx,6 - mov [edi+offs_mat_name],ebx - sub ebx,6 - ;*** (1) *** - .cycle_0: ;цикл для поиска цвета материала - add esi,dword[esi+2] - cmp word[esi],0xa010 - je @f - cmp ecx,esi - jg .cycle_0 ;пока не достигнута грница старшего блока - jmp .end_material ;если не нашли цвет материала - @@: - ;если нашли цвет материала + mov ebx,[f_data] + xor ecx,ecx + cmp word[ebx],CHUNK_MATERIAL + jne .no_material + mov ecx,ebx + add ecx,dword[ecx+2] ;граница блока + add ebx,6 + cmp word[ebx],CHUNK_MATNAME + jne .no_material + ;*** (0) *** + mov esi,ebx + add ebx,6 + mov [edi+offs_mat_name],ebx + sub ebx,6 + ;*** (1) *** + .cycle_0: ;цикл для поиска цвета материала + add esi,dword[esi+2] + cmp word[esi],0xa010 + je @f + cmp ecx,esi + jg .cycle_0 ;пока не достигнута грница старшего блока + jmp .end_material ;если не нашли цвет материала + @@: + ;если нашли цвет материала + add esi,6 + cmp word[esi],0x0011 + jne .end_material add esi,6 - cmp word[esi],0x0011 - jne .end_material - add esi,6 - mov dl,byte[esi] - mov [edi+offs_mat_col_ambient+2],dl - mov dx,word[esi+1] - ror dx,8 - mov [edi+offs_mat_col_ambient],dx - ;*** (2) *** - mov esi,ebx - .cycle_1: ;цикл для поиска цвета материала - add esi,dword[esi+2] - cmp word[esi],0xa020 - je @f - cmp ecx,esi - jg .cycle_1 ;пока не достигнута грница старшего блока - jmp .end_material ;если не нашли цвет материала - @@: - ;если нашли цвет материала + mov dl,byte[esi] + mov [edi+offs_mat_col_ambient+2],dl + mov dx,word[esi+1] + ror dx,8 + mov [edi+offs_mat_col_ambient],dx + ;*** (2) *** + mov esi,ebx + .cycle_1: ;цикл для поиска цвета материала + add esi,dword[esi+2] + cmp word[esi],0xa020 + je @f + cmp ecx,esi + jg .cycle_1 ;пока не достигнута грница старшего блока + jmp .end_material ;если не нашли цвет материала + @@: + ;если нашли цвет материала + add esi,6 + cmp word[esi],0x0011 + jne .end_material add esi,6 - cmp word[esi],0x0011 - jne .end_material - add esi,6 - mov dl,byte[esi] - mov [edi+offs_mat_col_diffuse+2],dl - mov dx,word[esi+1] - ror dx,8 - mov [edi+offs_mat_col_diffuse],dx - ;*** (3) *** - mov esi,ebx - .cycle_2: ;цикл для поиска цвета материала - add esi,dword[esi+2] - cmp word[esi],0xa030 - je @f - cmp ecx,esi - jg .cycle_2 ;пока не достигнута грница старшего блока - jmp .end_material ;если не нашли цвет материала - @@: - ;если нашли цвет материала + mov dl,byte[esi] + mov [edi+offs_mat_col_diffuse+2],dl + mov dx,word[esi+1] + ror dx,8 + mov [edi+offs_mat_col_diffuse],dx + ;*** (3) *** + mov esi,ebx + .cycle_2: ;цикл для поиска цвета материала + add esi,dword[esi+2] + cmp word[esi],0xa030 + je @f + cmp ecx,esi + jg .cycle_2 ;пока не достигнута грница старшего блока + jmp .end_material ;если не нашли цвет материала + @@: + ;если нашли цвет материала + add esi,6 + cmp word[esi],0x0011 + jne .end_material add esi,6 - cmp word[esi],0x0011 - jne .end_material - add esi,6 - mov dl,byte[esi] - mov [edi+offs_mat_col_specular+2],dl - mov dx,word[esi+1] - ror dx,8 - mov [edi+offs_mat_col_specular],dx + mov dl,byte[esi] + mov [edi+offs_mat_col_specular+2],dl + mov dx,word[esi+1] + ror dx,8 + mov [edi+offs_mat_col_specular],dx - .end_material: + .end_material: .no_material: popad ret @@ -714,6 +724,22 @@ end if stdcall [glRotatef], [angle_x],1.0,0.0,0.0 stdcall [glTranslatef], [edi+offs_obj_x_centr],[edi+offs_obj_y_centr],[edi+offs_obj_z_centr] +if version_edit eq 0 + ;рисование граней с использованием цветов материалов + bt dword[draw_mode],bit_faces_mat + jnc @f + mov eax,[edi+offs_obj_mat1_data] + .b_found: + cmp eax,0 + je .end_triangles + mov ebx,eax + stdcall get_mat_color, eax + stdcall draw_3d_faces_color, edi,ebx,eax + stdcall found_mat_faces, ebx + jmp .b_found + @@: +end if + ;рисование точек bt dword[draw_mode],bit_vertexes jnc .end_points @@ -863,7 +889,7 @@ SetLight: align 4 mnu_vertexes_on: or dword[draw_mode], 1 shl bit_vertexes - and dword[draw_mode], not (1 shl bit_faces) ;выключаем режим рисования граней (что-бы не мешали) + and dword[draw_mode], not ((1 shl bit_faces)+(1 shl bit_faces_mat)) ;выключаем режимы рисования, которые могут мешать call update_obj ret @@ -871,7 +897,7 @@ mnu_vertexes_on: align 4 mnu_edges_on: or dword[draw_mode], 1 shl bit_faces - and dword[draw_mode], not ((1 shl bit_vertexes)+(1 shl bit_faces_fill)) + and dword[draw_mode], not ((1 shl bit_vertexes)+(1 shl bit_faces_fill)+(1 shl bit_faces_mat)) call update_obj ret @@ -879,7 +905,7 @@ mnu_edges_on: align 4 mnu_faces_on: or dword[draw_mode], (1 shl bit_faces)+(1 shl bit_faces_fill) - and dword[draw_mode], not (1 shl bit_vertexes) + and dword[draw_mode], not ((1 shl bit_vertexes)+(1 shl bit_faces_mat)) call update_obj ret @@ -908,6 +934,13 @@ update_obj: else +;включаем режим рисования сплошных граней +align 4 +mnu_faces_mat: + or dword[draw_mode], (1 shl bit_faces_mat) + call update_obj + ret + align 4 update_obj: push eax ebx @@ -918,12 +951,120 @@ push eax ebx add ebx,dword[open_file_data] ;получаем значение сдвига в памяти cmp word[ebx],CHUNK_OBJBLOCK jne @f - add eax,14 ;14=list_offs_obj3d - stdcall draw_3d, eax + add eax,list_offs_obj3d + stdcall draw_3d,eax @@: pop ebx eax ret +;input: +; p_mat - указатель на данные предыдущего материала +align 4 +proc found_mat_faces uses ebx, p_mat:dword + mov eax,[p_mat] + add eax,[eax+2] + cmp word[eax],CHUNK_FACEMAT + je @f + xor eax,eax + @@: + ret +endp + +align 4 +proc get_mat_color uses ebx ecx edx edi esi, p_mat:dword + stdcall [tl_node_poi_get_info], tree1,0 + mov ecx,eax + .cycle_0: + cmp ecx,0 + je .cycle_0_end + stdcall [tl_node_poi_get_data], tree1,ecx + mov ebx,[eax] ;получаем значение сдвига выбранного блока + add ebx,[open_file_data] + cmp word[ebx],CHUNK_MATERIAL + jne .end_add_p3 + add eax,list_offs_obj3d + mov esi,[eax+offs_mat_name] + cmp esi,0 + jne @f + ;init material + stdcall mat_init,eax,ebx + mov esi,[eax+offs_mat_name] + @@: + mov edi,[p_mat] + mov eax,5 + add edi,eax +align 4 + @@: + cmp al,0 + je .found + lodsb + inc edi + cmp byte[edi],al + je @b + .end_add_p3: + stdcall [tl_node_poi_get_next_info], tree1,ecx + mov ecx,eax ;переходим к следущему узлу + jmp .cycle_0 + .cycle_0_end: + + .no_found: + xor eax,eax + jmp .end_f + .found: + stdcall [tl_node_poi_get_data], tree1,ecx + add eax,list_offs_obj3d + mov eax,[eax+offs_mat_col_diffuse] + .end_f: + ret +endp + +align 4 +proc draw_3d_faces_color o_data:dword, p_mat:dword, color:dword +pushad + stdcall [glPolygonMode], GL_FRONT_AND_BACK,GL_FILL + stdcall [glColor3ub],[color+2],[color+1],[color] + stdcall [glBegin],GL_TRIANGLES + mov edi,[o_data] + mov esi,[p_mat] + add esi,6 + @@: + lodsb + cmp al,0 + jne @b + movzx ecx,word[esi] ;ecx - число граней с данным материалом + mov edx,[edi+offs_obj_poi_data] +align 4 + @@: + add esi,2 + ;word[esi] - номер треугольника + movzx ebx,word[esi] + shl ebx,3 + add ebx,[edi+offs_obj_tri_data] + + movzx eax,word[ebx] ;1-я вершина + imul eax,12 ;float(x,y,z) + add eax,edx + stdcall [glVertex3f], [eax],[eax+4],[eax+8] + + movzx eax,word[ebx+2] ;2-я вершина + imul eax,12 ;float(x,y,z) + add eax,edx + stdcall [glVertex3f], [eax],[eax+4],[eax+8] + + movzx eax,word[ebx+4] ;3-я вершина + imul eax,12 ;float(x,y,z) + add eax,edx + stdcall [glVertex3f], [eax],[eax+4],[eax+8] + + dec ecx + jnz @b + stdcall [glEnd] + +.end_f: +popad + ret +endp + end if align 4 diff --git a/programs/develop/info3ds/toolbar.png b/programs/develop/info3ds/toolbar.png index faaca2607a0bae003f3edd23baf1944489f986b8..73dca94bb084ffdff666e84101ccfbbf7c7a8ee5 100644 GIT binary patch literal 3541 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