home *** CD-ROM | disk | FTP | other *** search
- ; ///////////////////////////////////////////////////////////////////////////
- ; Vrsmooth.asm - The inner loop of a program to draw voxel terrain
- ; Er um, this code is copyright @1994 Matt Howard, and stuff.
- ; But why copyright a program? It's just an instrument of the imperialist
- ; capatalist regime. In a true socialist society, we'd all share our code.
- ; And someone would tape Bill Gates mouth shut. Harmony would prevail.
- ; But anyway... here's the code...
- ; Oh, BTW, this performs the same function as VOXROW.asm, but w/
- ; smooth mountains
- ; /////////////////////////////////////////////////////////////////////////
- .DATA?
- h_inc DD ? ; height increment on screen per pixel
- c_inc DD ? ; color increment on screen per pixel
- last_x DB ? ; saves last map x
- last_y DB ? ; saves last map y
- last_height DW ? ; saved last height
- vox_cur_change DD ? ; current height change point
- .CODE
- .386
-
- X_LOC_BOUNDER equ 00ffffffh
- Y_LOC_BOUNDER equ 0ff000000h
- VOX_FP_SHIFT equ 10h
- LIGHT_FP_SHIFT equ 08h
- ALT_TO_COL_DIFF equ 0ffffh
- G_TABLE_SHIFT equ 9
- G_TABLE_ADJUST equ 100h
- LIGHT_AND equ 0f0h
- COLOR_AND equ 0fh
- HEIGHT_CHANGE_SHIFT equ 10h
- H_TABLE_SHIFT equ 6h
- MAX_TABLED_HC_INTP equ 040h
- LEV_LOC equ 4h
- COL_LOC equ 6h
- HCP_SIZE equ 8h
- HEIGHT_AND equ 0000ffffh
- X_CORRECT equ 8h
- Y_CORRECT equ 10h
-
- EXTRN "C", x_inc:DWORD; speed at which to go across map in x
- EXTRN "C", y_inc:DWORD; speed at which to go across map in y
- EXTRN "C", x_loc:DWORD; fixed-point x loc in map
- EXTRN "C", y_loc:DWORD; fixed-point y loc in map
- EXTRN "C", vox_buff:DWORD; buffer in which to draw
- EXTRN "C", starting_y:WORD; highest value to starting drawing at
- EXTRN "C", cur_scaler:DWORD ; array holds data to scale altitudes to screen
- EXTRN "C", alt_array:DWORD ; grid of altitudes
- EXTRN "C", prev_vox_colors:DWORD ; array to save last trace colors
- EXTRN "C", prev_vox_heights:DWORD ; array to save last trace heights
- EXTRN "C", g_table:DWORD ; scaler to get gauraud interpolation w/o division
- EXTRN "C", h_table:DWORD ; scaler to get line interpolation w/o division
- EXTRN "C", y_jumps:DWORD ; scaler to get y line offset w/o multiplication
- EXTRN "C", WINDOW_HEIGHT:WORD ; height of view window
- EXTRN "C", v_horiz_length:DWORD ; length horizontally of current vox run
- EXTRN "C", PHYS_SCREEN_WIDTH:DWORD ; length of physical screen
- EXTRN "C", PHYS_SCREEN_HEIGHT:DWORD ; length of physical screen
- EXTRN "C", vox_change_table:DWORD ; keeps track of the height changes
- EXTRN "C", v_light_table:DWORD ; table of values to change light
-
- PUBLIC Draw_Vox_Row_Smooth_
-
- Draw_Vox_Row_Smooth_ PROC NEAR C
-
- pushad
-
- mov esi, v_horiz_length
- dec esi
-
- ; initialize map position trackers
- mov eax, x_loc
- sar eax, X_CORRECT
- mov ebx, y_loc
- sar ebx, Y_CORRECT
- mov edx, y_inc
- sar edx, Y_CORRECT
- mov y_inc, edx
- mov edx, x_inc
- sar edx, X_CORRECT
- mov x_inc, edx
-
- ; save starting y val in register
- xor ebp, ebp
- mov bp, starting_y
-
- ; get absolute values for map movements
- mov edx, x_inc
- cmp edx,00000000h
- jge ABS_OK1
- mov edi,edx
- mov edx,0
- sub edx, edi
- ABS_OK1:
- mov ecx, y_inc
- cmp ecx,000000000h
- jge ABS_OK2
- mov edi, ecx
- mov ecx, 0
- sub ecx, edi
- ABS_OK2:
-
- ; decide which movement is greater
- cmp edx, ecx
- jge VOX_SETUP_X_START
-
- ; put the array of height changes in register
- mov edi, vox_change_table
-
- ;make sure first pass dosen't get skipped (we need at least one change point
- mov last_y, bh
- dec last_y
-
- mov ecx, y_inc
- cmp ecx, 00000000h
- je FIX_Y_INC
- FIX_Y_DONE:
- VOX_SETUP_Y:
-
- cmp bh, last_y
- jne new_value_y
-
- ; update positions in map
- mov edx, y_inc
- add ebx, edx
- mov edx, x_inc
- add eax, edx
-
- ; and loop
- dec esi
- jmp VOX_SETUP_Y
-
- new_value_y:
- ; clear gen purpose regs
- xor edx,edx
- xor ecx,ecx
-
- ; save new position
- mov last_y, bh
-
- ; get x,y location of next pixel
- mov dh, bh
- mov dl, ah
-
- ; get altitude
- add edx, alt_array
- mov cl, [edx]
-
- ; get color
- ; Note: altitude & color array are next to each other
- ; in memory for speed
- add edx, ALT_TO_COL_DIFF
- mov dl, [edx]
- mov [edi+COL_LOC],dl
- ; scale altitude
- ; note: ecx added twice since it is word
- mov edx, cur_scaler
- add edx, ecx
- add edx, ecx
- mov cx, [edx]
-
- ; add base value and clip against screen for final value
- add cx, bp
-
- ; too high
- jns not_too_high
- mov cx, 0
-
- not_too_high:
-
- ; make another height change point
- mov [edi], esi
- mov [edi+LEV_LOC], cx
- add edi, HCP_SIZE
-
- ; update positions in map
- mov edx, y_inc
- add ebx, edx
- mov edx, x_inc
- add eax, edx
-
- ; and loop
- dec esi
- cmp esi, 0FFFFFFFFh
- jge VOX_SETUP_Y
- jmp VOX_SETUP_DONE
-
- VOX_SETUP_X_START:
-
- ; put the array of height changes in register
- mov edi, vox_change_table
-
- ;make sure first pass dosen't get skipped (we need at least one change point
- mov last_x, ah
- dec last_x
-
- mov edx, x_inc
- cmp edx, 00000000h
- je FIX_X_INC
- FIX_X_DONE:
- VOX_SETUP_X:
-
- cmp ah, last_x
- jne new_value_x
-
- ; update positions in map
- mov edx, y_inc
- add ebx, edx
- mov edx, x_inc
- add eax, edx
-
- ; and loop
- dec esi
- jmp VOX_SETUP_X
-
- new_value_x:
- ; clear gen purpose regs
- xor edx,edx
- xor ecx,ecx
-
- ; save new position
- mov last_x, ah
-
- ; get x,y location of next pixel
- mov dh, bh
- mov dl, ah
-
- ; get altitude
- add edx, alt_array
- mov cl, [edx]
-
- ; get color
- ; Note: altitude & color array are next to each other
- ; in memory for speed
- add edx, ALT_TO_COL_DIFF
- mov dl, [edx]
- mov [edi+COL_LOC],dl
- ; scale altitude
- ; note: ecx added twice since it is word
- mov edx, cur_scaler
- add edx, ecx
- add edx, ecx
- mov cx, [edx]
-
- ; add base value and clip against screen for final value
- add cx, bp
-
- ; too high
- jns not_too_high_x
- mov cx, 0
-
- not_too_high_x:
-
- ; make another height change point
- mov [edi], esi
- mov [edi+LEV_LOC], cx
- add edi, HCP_SIZE
-
- ; update positions in map
- mov edx, y_inc
- add ebx, edx
- mov edx, x_inc
- add eax, edx
-
- ; and loop
- dec esi
- cmp esi, 0FFFFFFFFh
- jge VOX_SETUP_X
- jmp VOX_SETUP_DONE
-
- VOX_SETUP_DONE:
- ; first run through voxels is done, now we must do the actual drawing
- ; we will use the change tables to interpolate the lines
-
- mov esi, v_horiz_length
- dec esi
-
- mov eax, vox_change_table
- mov vox_cur_change, eax
-
- VOX_DRAW_LOOP:
- xor ecx, ecx
- xor eax, eax
-
- mov edi, vox_cur_change
- cmp esi, [edi]
- je VOX_MAKE_CHANGE
- VOX_DRAW_CONTINUE:
-
- xor edi, edi
- shld ecx, ebp, HEIGHT_CHANGE_SHIFT
- and ecx, HEIGHT_AND
-
- add ebp, h_inc
- add edx, c_inc
-
- ; get difference in color
- ; Note: previous height and previous color are next to each other
- ; in memory for speed
- mov ebx, prev_vox_colors;
- add ebx, esi
- mov al, [ebx]
- mov [ebx], dh
-
- ; get previous y
- mov ebx, prev_vox_heights;
- ; note: esi added twice for since it is word
- add ebx, esi
- add ebx, esi
- mov di, [ebx]
- sub di, cx
- jbe NO_DRAW
-
- mov [ebx], cx ; save current value for next round, this seems
- ; out of place, but helps speed
-
- xor ebx, ebx
-
- ; get gauraud interpolation value
- mov ebx, edi
- shl ebx, G_TABLE_SHIFT
- add eax, G_TABLE_ADJUST
- add eax, ebx
- xor ebx,ebx
- mov bl, dh
- sub eax, ebx
- ; adjust for long
- add eax, eax
- add eax, g_table
- mov ax, [eax]
-
- ; get screen starting pos
- shl ecx, 2
- add ecx, y_jumps
- mov ecx, [ecx]
- add ecx, esi
- add ecx, vox_buff
-
- ; set up values for gauroud loop
- mov bh, bl
- xor bl,bl
-
- VOX_IN_LOOP:
-
- ; note: to achieve super speed,
- ; fixed point light is exactly 8 bits in the decimal
- ; this way, the integer portion can be accessed
- ; directly through byte register "bh"
- ; cutting inner loop total to 5 instructions! (including counter update)
-
- ; get the color val and throw it on that screen
- mov [ecx], bh
-
- ; update light val and screen pos
- add ecx, PHYS_SCREEN_WIDTH
- add bx, ax
-
- ; and loop
- dec edi
- jnz VOX_IN_LOOP
-
- NO_DRAW:
-
- ; and loop
- dec esi
- jns VOX_DRAW_LOOP
-
- popad
- ret
-
- ; all right think of these as functions, which happen to have intimate knowledge
- ; of how the calling function works, and what it is doing at the moment
- ; they're placed away from the main body, because they are all exceptions
- ; we want the normal path to be as fast as possible, and conditional jumps
- ; takes one third the time if the jump is not made, so we want more
- ; common conditions to do less jumping (phew, everybody got that?)
-
- ; vox_make_change- loads ebp with new y value, edx with a new color value
- ; and sets h_inc and c_inc to the appropriate interpolation values
- VOX_MAKE_CHANGE:
- xor ebp, ebp
- xor edx, edx
- mov bp, [edi+LEV_LOC]
- mov dl, [edi+COL_LOC]
-
- ; light color (easiest place to do it)
- mov ebx, v_light_table
- mov dl, [ebx+edx]
-
- mov ecx, esi
- add edi, HCP_SIZE
- sub ecx, [edi]
- cmp ecx, PHYS_SCREEN_WIDTH
- jg CORRECT_CHANGE
- CORRECT_DONE:
- mov al, [edi+COL_LOC]
-
- ; light destination color
- mov ebx, v_light_table
- mov al, [ebx+eax]
-
- ; get gauraud interpolation value
- mov ebx, ecx
- shl ebx, G_TABLE_SHIFT
- add ebx, eax
- add ebx, G_TABLE_ADJUST
- sub ebx, edx
- ; adjust for word
- add ebx, ebx
- add ebx, g_table
- mov ax, [ebx]
- mov c_inc, eax
-
- ; now we need the height interpolation
- mov ax, [edi+LEV_LOC]
- ; can we get it from the table?
- cmp ecx, MAX_TABLED_HC_INTP
- jge HC_INTP_DIV
-
- ; yes, we can
- mov ebx, eax
- add ebx, PHYS_SCREEN_HEIGHT
- sub ebx, ebp
- shl ebx, H_TABLE_SHIFT
- add ebx, ecx
- ; adjust for long
- shl ebx, 2
- ; load it up
- add ebx, h_table
- mov eax, [ebx]
- mov h_inc, eax
- VC_CONTINUE:
- ; adjust color and height to be fixed points
- mov dh, dl
- mov dl, 0
- shl ebp, HEIGHT_CHANGE_SHIFT
- xor eax, eax
- mov vox_cur_change, edi
- jmp VOX_DRAW_CONTINUE
-
- ; hp_intp_div gets height interpolation value by straight division (not enough memory to
- ; make a table for all interpolations
- HC_INTP_DIV:
- sub eax, ebp
- mov ebx, edx
- mov edx, eax
- xor eax, eax
- shrd eax,edx, HEIGHT_CHANGE_SHIFT
- sar edx, HEIGHT_CHANGE_SHIFT
- idiv ecx
- mov edx, ebx
- mov h_inc, eax
- jmp VC_CONTINUE
-
- ; makes sure the length of next interpolation is not longer than the screen
- ; (which causes a page fault, if it is)
- CORRECT_CHANGE:
- mov ecx, PHYS_SCREEN_WIDTH
- jmp CORRECT_DONE
-
- ; makes sure x_inc isn't 0 (vox_setup may otherwise be an infinite loop)
- FIX_X_INC:
- inc edx
- mov x_inc, edx
- jmp FIX_X_DONE
-
- ; same, but for y_inc
- FIX_Y_INC:
- inc ecx
- mov y_inc, ecx
- jmp FIX_Y_DONE
-
- Draw_Vox_Row_Smooth_ ENDP
-
- END
-