;************************************************************************************* ; MODULE: TMAP16.ASM DATE: DECEMBER 28,1994 ; AUTHOR: SEAN M. KESSLER ; TARGET: 16 BIT TARGET ; FUNCTION : TEXTURE MAPPING POLYGONS IN PERSPECTIVE ;************************************************************************************* .MODEL LARGE C .386 .DATA bmData@@mSrcWidth DW 00h bmData@@mSrcHeight DW 00h bmData@@mlpSrcPtr DD 00h bmData@@mDstWidth DW 00h bmData@@mDstHeight DW 00h bmData@@mlpDstPtr DD 00h MINVALUE EQU -32767 MAXVALUE EQU 32767 MINVERTEX EQU 3 PRECISION EQU 16384 .CODE LOCALS INCLUDE ..\COMMON\COMMON.INC INCLUDE ..\ENGINE\TMAP16.INC round MACRO varOne mov eax,varOne ; move varOne into eax register mov ebx,eax ; move varOne into ebx register and ebx,00003FFFh ; get remainder into ebx register shr eax,14 ; get whole number to eax register cmp ebx,8192 ; if remainder > 8192, increment eax db 7Eh ; the next 2 bytes comprise "jle +2" (ie) db 02h ; jump passed the increment eax instruction inc eax ; increment value in eax ENDM multiply MACRO varOne,varTwo push bx ; save bx register mov ax,varOne ; move varOne into ax register mov bx,varTwo ; move varTwo into bx register imul bx ; perform the multiply result to dx:ax push ax ; save ax register result movzx eax,dx ; move dx register to eax zero extend shl eax,16 ; shift eax left by a word pop ax ; restore ax register result pop bx ; restore bx register ENDM divide MACRO varOne,varTwo push ebx ; save ebx register mov ebx,varTwo ; move varTwo into ebx register mov eax,varOne ; move varOne into eax register cdq ; convert doubleword in eax to quadword at edx:eax idiv ebx ; divide eax/ebx result to eax, remainder to edx pop ebx ; restore ebx register ENDM getPoint MACRO segment,offset,index push si ; save source index register push ds ; save data segment register push cx ; save cx register push segment ; save segment on stack pop ds ; restore to data segment mov ax,index ; move index to ax register shl ax,02h ; multiply ax by size of far pointer mov si,offset ; now move offset address to si add si,ax ; add in the increment value xor eax,eax ; clear out eax register mov ax,ds:[si].Point@@x ; get the x-value to ax register xor ebx,ebx ; clear out ebx register mov bx,ds:[si].Point@@y ; get the y-value to bx register pop cx ; restore saved cx register pop ds ; restore saved data segment pop si ; restore save source index register ENDM _initEdge proc far ; void initEdge(short edgeType,PureEdge *lpEdge); push bp ; save callers stack frame mov bp,sp ; create new stack frame push di ; save callers destination index register mov es,[bp+10] ; move segment of data to extra segment mov di,[bp+8] ; move offset of data to destination index register assume es ; now assume extra segment for segment loads. call _getMinMaxInfo ; find minimum and maximum vertexes cmp ax,00h ; make sure previous call returned success jne @@return ; if not then we should leave push word ptr[bp+6] ; push edgeType (-1:leftEdge,1:rightEdge) push [di].PureEdge@@mStartVertex ; push startVertex call _setupEdge ; now setup the edge add sp,04h ; readjust the stack @@return: assume @data ; assume old data segment for segment loads pop di ; restore destination index register pop bp ; restore callers stack frame retf ; return to caller _initEdge endp _getMinMaxInfo proc near ; short getMinMaxInfo(void) LOCAL yMin:WORD,yMax:WORD=LocalLength push bp ; save callers stack frame mov bp,sp ; create new frame sub sp,LocalLength ; adjust stack to handle local variables push cx ; save callers cx register push si ; save callers source index register push ds ; save callers data segment register cmp [di].PureEdge@@mNumVertexes,MINVERTEX ; make sure have at least three vertexes jl @@error ; otherwise we've got a problem mov yMin,MINVALUE ; start yMin with some low value mov yMax,MAXVALUE ; start yMax with some high value xor cx,cx ; start at index 0 mov ds,[di].PureEdge@@mlpDstList ; segment address of (Point *) to extra segment register mov si,[di].PureEdge@@mlpDstList+2 ; offset address of (Point *) to source index register @@iterator: ; loop top mov bx,ds:[si].Point@@y ; move point::y to bx register cmp bx,yMin ; compare with current yMin value jg @@greater ; point::y greater than current yMin @@nexttest: ; if I handle the greater condition, still need to do less cmp bx,yMax ; compare with current yMax value jl @@less ; point::y less than current yMax jmp @@looptest ; nuthin continue with test @@greater: ; handle greater equal condition mov yMin,bx ; set yMin to bx register mov [di].PureEdge@@mMinVertex,cx ; move index number of vertex to mMinVertex jmp @@nexttest ; go perform next test @@less: ; handle less equal condition mov yMax,bx ; set yMax to bx register mov [di].PureEdge@@mMaxVertex,cx ; update mMaxVertex with current index @@looptest: ; falls through to loop add si,04h ; add 2 bytes to si to bump to next (Point*) inc cx ; increment cx cmp cx,[di].PureEdge@@mNumVertexes ; have we reached the number of vertexes yet? jl @@iterator ; still more vertexes push [di].PureEdge@@mMaxVertex ; save mMaxVertex pop [di].PureEdge@@mStartVertex ; restore it to mStartVertex jmp @@ok ; ok we've got good number of vertexes @@error: ; setup for error return code mov ax,01h ; move 01h into ax to indicate error jmp @@return ; jump to return label @@ok: ; setup for success return code xor ax,ax ; clear out ax register @@return: ; return label pop ds ; restore callers extra segment register pop si ; restore callers source index register pop cx ; restore callers cx register add sp,LocalLength ; readjust stack for local variables pop bp ; restore old frame retn ; return to caller _getMinMaxInfo endp _setupEdge proc near ; short setupEdge(short edgeType,short startVertex) LOCAL nextVertex:WORD,xDestWidth:WORD,yDestHeight:DWORD=LocalLength push bp ; save old stack frame mov bp,sp ; create new stack frame sub sp,LocalLength ; make room for local variables push si ; save source index register push ds ; save data segment register push word ptr[bp+6] ; save edgeType on stack pop [di].PureEdge@@mEdgeDirection ; restore edgeType to mEdgeDirection push word ptr[bp+4] ; save startVertex on stack pop [di].PureEdge@@mStartVertex ; restore startVertex to mStartVertex @@forever: ; forever loop label mov bx,[di].PureEdge@@mStartVertex ; move mStartVertex to bx register cmp bx,[di].PureEdge@@mMinVertex ; is mStartVertex same as mMinVertex ?? je @@error ; if yes then return error status add bx,[di].PureEdge@@mEdgeDirection ; add edge direction to mStartVertex mov nextVertex,bx ; move result to nextVertex mov bx,[di].PureEdge@@mNumVertexes ; move number of vertexes to bx register cmp nextVertex,bx ; compare nextVertex to number of vertexes jge @@zervert ; nextVertex is greater eq number of vertexes cmp nextVertex,00h ; compare nextVertex to zero jl @@adjVert ; nextVertex is less than zero jmp @@bypass ; nextVertex is fine @@zervert: ; handle nextVertex>=number of vertexes mov nextVertex,00h ; set nextVertex to zero jmp @@bypass ; jump over next conditional @@adjVert: ; handle nextVertex<0 dec bx ; decrement value count in bx register mov nextVertex,bx ; set nextVertex to (numVertex-1). @@bypass: getPoint [di].PureEdge@@mlpDstList,[di].PureEdge@@mlpDstList+2,nextVertex push bx ; dstList[nextVertex].y() in bx , save it getPoint [di].PureEdge@@mlpDstList,[di].PureEdge@@mlpDstList+2,[di].PureEdge@@mStartVertex pop ax ; restore first x-point to ax sub ax,bx ; now subtract second x-point mov [di].PureEdge@@mRemainingScanLines,ax ; result is mRemainingScanLines cmp ax,00h ; check scanlines==0 je @@loopNext ; if it's zero, continue mov yDestHeight,eax ; set yDestHeight push nextVertex ; save nextVertex value pop [di].PureEdge@@mCurrentEdgeEnd ; restore it to mCurrentEdgeEnd getPoint [di].PureEdge@@mlpSrcList+2,[di].PureEdge@@mlpSrcList,[di].PureEdge@@mStartVertex multiply ax,PRECISION ; multiply mxSource by PRECISION mov [di].PureEdge@@mxSource,eax ; move srcList[mStartVertex].x() to mxSource multiply bx,PRECISION ; multiply mySource by PRECISION mov [di].PureEdge@@mySource,eax ; move srcList[mStartVertex].y() to mySource getPoint [di].PureEdge@@mlpSrcList+2,[di].PureEdge@@mlpSrcList,nextVertex ; get source point multiply ax,PRECISION mov ebx,[di].PureEdge@@mxSource ; mxSource to bx register sub eax,ebx ; (ie) mlpSrcList[nextVertex].x-mxSource-->ax divide eax,yDestHeight ; divide by yDestHeight, this is mxSourceStep mov [di].PureEdge@@mxSourceStep,eax ; move eax register into mxSourceStep getPoint [di].PureEdge@@mlpSrcList+2,[di].PureEdge@@mlpSrcList,nextVertex ; get source point mov eax,ebx ; move point.y into ax register multiply ax,PRECISION mov ebx,[di].PureEdge@@mySource ; mySource to bx register sub eax,ebx ; (ie) mlpSrcList[nextVertex].y-mySource-->ax divide eax,yDestHeight ; divide by yDestHeight, this is mySourceStep mov [di].PureEdge@@mySourceStep,eax ; move eax register into mySourceStep getPoint [di].PureEdge@@mlpDstList,[di].PureEdge@@mlpDstList+2,[di].PureEdge@@mStartVertex mov [di].PureEdge@@mxDestLocation,ax ; mxDestLocation=mDstList[mStartVertex].x() getPoint [di].PureEdge@@mlpDstList,[di].PureEdge@@mlpDstList+2,nextVertex ; get dstList[nextVertex] sub ax,[di].PureEdge@@mxDestLocation ; get the width of the segment mov xDestWidth,ax ; move width into xDestWidth cmp xDestWidth,00h ; is the direction negative (ie) left jl @@negWidth ; yes, handle negative direction mov [di].PureEdge@@mxDirection,01h ; set right direction indicator mov [di].PureEdge@@mxErrorTerm,00h ; set mxErrorTerm to zero movzx eax,xDestWidth ; move xDestWidth to eax zero extend movzx ebx,[di].PureEdge@@mRemainingScanLines ; move mRemainingScanLines to ebx zero extend divide eax,ebx ; eax=xDestWidth/mRemainingScanLines mov [di].PureEdge@@mxStep,ax ; move result into mxStep jmp @@syncOne ; jump over following handler @@negWidth: ; handle negative direction mov [di].PureEdge@@mxDirection,-1 ; set left direction indicator neg xDestWidth ; negate the width (ie) make it positive mov ax,01h ; move a 1 into ax register sub ax,[di].PureEdge@@mRemainingScanLines ; subtract remaining scan lines from 1 mov [di].PureEdge@@mxErrorTerm,ax ; move result to mxErrorTerm movzx eax,xDestWidth ; move xDestWidth to eax zero extend movzx ebx,[di].PureEdge@@mRemainingScanLines ; move mRemainingScanLines to ebx zero extend divide eax,ebx ; eax=xDestWidth/mRemainingScanLines neg eax ; negate the result mov [di].PureEdge@@mxStep,ax ; move result back into mxStep @@syncOne: ; synchronization address movzx eax,xDestWidth ; move xDestWidth into eax register, zero extend movzx ebx,[di].PureEdge@@mRemainingScanLines ; move mRemainingScanLines into ebx register divide eax,ebx ; divide xDestWidth/mRemainingScanLines mov [di].PureEdge@@mxAdjustUp,dx ; move remainder into mxAdjustUp push [di].PureEdge@@mRemainingScanLines ; save mRemainingScanLines pop [di].PureEdge@@mxAdjustDown ; restore mRemainingScanLines into mxAdjustDown jmp @@ok ; jump over forever loop @@loopNext: ; forever loop address push nextVertex ; save nextVertex on stack pop [di].PureEdge@@mStartVertex ; restore to mStartVertex jmp @@forever ; continue with loop @@error: ; error handler mov ax,01h ; set ax register to 01h to indicate failure jmp @@return ; jump over to return label @@ok: ; success handler xor ax,ax ; clear out ax register to handle success @@return: ; return label pop ds ; restore data segment register pop si ; restore source index register add sp,LocalLength ; readjust stack for local variables pop bp ; restore old stack frame retn ; return to caller _setupEdge endp _increment proc near ; short increment(PureEdge *lpEdge) push bp ; save callers stack frame mov bp,sp ; create new stack frame push es ; save extra segment register push di ; save destination index register mov es,[bp+6] ; move segment of data to extra segment mov di,[bp+4] ; move offset of data to destination index register assume es ; now assume extra segment for segment loads. dec [di].PureEdge@@mRemainingScanLines ; decrement mRemainingScanLines cmp [di].PureEdge@@mRemainingScanLines,00h ; compare mRemainingScanLines to zero je @@newEdge ; no more scan lines, try to get to next edge jmp @@syncOne ; more scan lines, keep going @@newEdge: ; new edge handler push [di].PureEdge@@mEdgeDirection ; save edgeDirection push [di].PureEdge@@mCurrentEdgeEnd ; save currentEdge end (ie) nextEdge index call _setupEdge ; attempt to setup new edge add sp,04h ; readjust stack cmp ax,01h ; did prior call fail? je @@error ; yes, no more edges jmp @@ok ; no, keep going @@syncOne: ; synchronizing address mov eax,[di].PureEdge@@mxSourceStep ; get mxSourceStep to eax register add eax,[di].PureEdge@@mxSource ; add in mxSource mov [di].PureEdge@@mxSource,eax ; replace mxSource with new value mov eax,[di].PureEdge@@mySourceStep ; get mySourceStep into eax register add eax,[di].PureEdge@@mySource ; add in mySource mov [di].PureEdge@@mySource,eax ; replace mySource with new value mov ax,[di].PureEdge@@mxDestLocation ; get mxDestLocation into ax register add ax,[di].PureEdge@@mxStep ; add in mxStep mov [di].PureEdge@@mxDestLocation,ax ; replace mxDestLocation with new value mov ax,[di].PureEdge@@mxErrorTerm ; get mxErrorTerm to ax register add ax,[di].PureEdge@@mxAdjustUp ; add in mxAdjustUp mov [di].PureEdge@@mxErrorTerm,ax ; replace mxErrorTerm with new value cmp ax,00h ; now compare result to 00h jg @@adjTerm ; result is greater than zero jmp @@ok ; result is less equal to zero, we're done @@adjTerm: mov ax,[di].PureEdge@@mxDestLocation ; get mxDestLocation to ax register add ax,[di].PureEdge@@mxDirection ; add in mxDirection mov [di].PureEdge@@mxDestLocation,ax ; replace mxDestLocation with new value mov ax,[di].PureEdge@@mxErrorTerm ; move mxErrorTerm into ax register sub ax,[di].PureEdge@@mxAdjustDown ; add in mxAdjustDown mov [di].PureEdge@@mxErrorTerm,ax ; replace mxErrorTerm with new value @@ok: ; ok handler address xor ax,ax ; set 00h into ax register jmp @@return ; jump passed next block @@error: ; error handler address mov ax,01h ; set 01h into ax register @@return: ; return handler assume @data ; assume old data segment for segment loads pop di ; restore destination index register pop es ; restore extra segment register pop bp ; restore stack frame retn ; return to caller _increment endp _mapTexture proc far ; void mapTexture(PureMap *lpTextureMap) push bp ; save stack frame mov bp,sp ; create new frame push di ; save destination index register push si ; save source index register push ds ; save data segment register mov es,word ptr[bp+8] ; move segment (PureMap*) to es register mov di,word ptr[bp+6] ; move offset (PureMap*) to destination index register push es:[di].PureMap@@mlpLeftEdge+2 ; save segment mlpLeftEdge pop ds ; restore segment mlpLeftEdge to ds register mov si,es:[di].PureMap@@mlpLeftEdge ; move offset mlpLeftEdge to si register mov cx,ds:[si].PureEdge@@mMaxVertex ; move left edge max vertex to ax register getPoint ds:[si].PureEdge@@mlpDstList,ds:[si].PureEdge@@mlpDstList+2,cx mov es:[di].PureMap@@myValue,bx ; myValue=mLeftEdge[mLeftEdge.maxVertex()].y() @@forever: ; while(TRUE) push es ; push segment (PureMap*) push di ; push offset (PureMap*) call _scanOutputLine ; call scanOutputLine add sp,04h ; readjust stack push word ptr es:[di].PureMap@@mlpLeftEdge+2 ; push segment mlpLeftEdge push word ptr es:[di].PureMap@@mlpLeftEdge ; push offset mlpLeftEdge call _increment ; increment along left edge add sp,04h ; readjust stack after call cmp ax,00h ; check return code jne @@return ; edge failed to increment, we're done push word ptr es:[di].PureMap@@mlpRightEdge ; push segment mlpRightEdge push word ptr es:[di].PureMap@@mlpRightEdge+2 ; push offset mlpRightEdge call _increment ; increment along right edge add sp,04h ; readjust stack after call cmp ax,00h ; check return code jne @@return ; edge failed to increment, we're done inc es:[di].PureMap@@myValue ; increment y() position jmp @@forever ; loop until all edges are completed @@return: ; return address label pop ds ; restore data segment register pop si ; restore source index re pop di ; restore destination index register pop bp ; restore old frame retf ; return to caller _mapTexture endp _scanOutputLine proc near push bp ; save stack frame mov bp,sp ; create new frame push es ; save extra segment push di ; save destination index register push ds ; save data segment register push si ; save source index register mov es,word ptr[bp+6] ; move segment (PureMap*) to extra segment register mov di,word ptr[bp+4] ; move offset (PureMap*) to destination index register push es:[di].PureMap@@mlpLeftEdge+2 ; save segment mlpLeftEdge pop ds ; restore segment mlpLeftEdge to data segment mov si,es:[di].PureMap@@mlpLeftEdge ; move offset mlpLeftEdge to source index reg mov eax,ds:[si].PureEdge@@mxSource ; move PureEdge::mxSource to eax register mov es:[di].PureMap@@mxSource,eax ; move PureEdge::mxSource to PureMap::mxSource mov eax,ds:[si].PureEdge@@mySource ; move PureEdge::mySource to eax register mov es:[di].PureMap@@mySource,eax ; move PureEdge::mySource to PureMap::mySource mov bx,ds:[si].PureEdge@@mxDestLocation ; move PureEdge::mxDestLocation to bx mov es:[di].PureMap@@mxDest,bx ; move PureEdge::mxDestLocation to PureMap::mxDest push word ptr es:[di].PureMap@@mlpRightEdge ; save segment mlpRightEdge pop ds ; restore segment mlpRightEdge to ds mov si,word ptr es:[di].PureMap@@mlpRightEdge+2 ; move offset mlpRightEdge to si xor eax,eax ; to clear out the high word of eax mov ax,ds:[si].PureEdge@@mxDestLocation ; move PureEdge.mxDestLocation to ax mov es:[di].PureMap@@mxDestMax,ax ; move PureEdge.mxDestLocation to PureMap.mxDestMap sub ax,bx ; mxDestMax-mxDest cmp ax,00h ; check if width is zero je @@return ; if width is zero just return mov es:[di].PureMap@@mDestWidth,eax ; move width into PureMap::mDestWidth mov eax,ds:[si].PureEdge@@mxSource ; move PureEdge::mxSource into eax sub eax,es:[di].PureMap@@mxSource ; subtract out PureMap::mxSource divide eax,es:[di].PureMap@@mDestWidth ; now divide by PureMap::mDestWidth mov es:[di].PureMap@@mxSourceStep,eax ; move new value to PureMap@@mxSourceStep mov eax,ds:[si].PureEdge@@mySource ; move PureEdge::mySource into eax sub eax,es:[di].PureMap@@mySource ; subtract out PureMap::mySource divide eax,es:[di].PureMap@@mDestWidth ; now divide by PureMap::mDestWidth mov es:[di].PureMap@@mySourceStep,eax ; move new value to PureMap@@mySourceStep @@xLoop: ; xLoop top mov ax,es:[di].PureMap@@mxDest ; move mxDest to ax register cmp ax,es:[di].PureMap@@mxDestMax ; compare mxDest to mxDestMax jge @@return ; if its greater equal return cmp es:[di].PureMap@@mxSource,00h ; compare mxSource to zero jl @@xFix ; if mxSource is less than zero, fix @@nxtChk: ; sync label to continue with checking cmp es:[di].PureMap@@mySource,00h ; compare mySource to zero jl @@yFix ; if mySource is less than zero, fix jmp @@syncOne ; everything ok, jump over block @@yFix: ; handle y-fixup mov es:[di].PureMap@@mySource,00h ; move zero to mySource jmp @@syncOne ; jump around next handler @@xFix: ; handle x-fixup mov es:[di].PureMap@@mxSource,00h ; move zero into mxSource jmp @@nxtChk ; now look at y-value @@syncOne: ; synchronization for conditionals push es ; save extra segment register mov eax,es:[di].PureMap@@mySource ; move PureMap@@mxSource to eax round eax ; convert and round push ax ; save result on stack mov eax,es:[di].PureMap@@mxSource ; move PureMap@@mySource to eax round eax ; convert and round shl eax,16 ; now shift eax left by 16 bits pop ax ; and restore yValue to low word movzx ebx,es:[di].PureMap@@mxDest ; move PureMap::mxDest to eax shl ebx,16 ; shift eax left 16 bits mov bx,es:[di].PureMap@@myValue ; move PureMap::myValue to ax call _putImageBits ; call put pixel handler pop es ; restore extra segment register mov eax,es:[di].PureMap@@mxSource ; move mxSource to eax register add eax,es:[di].PureMap@@mxSourceStep ; add in mxSourceStep mov es:[di].PureMap@@mxSource,eax ; move result to mxSource mov eax,es:[di].PureMap@@mySource ; move mySource into eax register add eax,es:[di].PureMap@@mySourceStep ; add in mySourceStep mov es:[di].PureMap@@mySource,eax ; move result to mySource inc es:[di].PureMap@@mxDest ; increment loop counter jmp @@xLoop ; loop through xLoop @@return: ; return sync label pop si ; restore source index register pop ds ; restore data segment register pop di ; restore destination index register pop es ; restore extra segment pop bp ; restore old stack frame retn ; return to caller _scanOutputLine endp _getSrcDataByte proc near ; BYTE getSrcDataByte(WORD row,WORD col) LOCAL addValue:DWORD=LocalLength push bp ; save old stack frame mov bp,sp ; create new stack frame sub sp,LocalLength ; adjust stack for local variable push bx ; save bx register push cx ; save cx register push dx ; save dx register push es ; save extra segment register push di ; save destination index register mov dx,word ptr[bp+04h] ; move row into dx register cmp dx,bmData@@mSrcHeight ; is row greater than bitmap height jge @@error ; if so then return cmp dx,00h ; is row less than zero jl @@error ; if so then return error movzx ebx,word ptr[bp+06h] ; move col into bx register, zero extended cmp bx,bmData@@mSrcWidth ; is col greater than bitmap width jge @@error ; if so then return cmp bx,00h ; is col less than zero jl @@error ; is so then return error movzx ecx,bmData@@mSrcWidth ; move width into cx register mov ax,bmData@@mSrcHeight ; move height into ax register push dx ; save dx register multiply ax,cx ; multiply width*height result to eax pop dx ; restore dx register mov addValue,eax ; store result to addValue multiply dx,cx ; multiply row*width result to eax add eax,ecx ; add (row*width)+width sub addValue,eax ; calculate addValue-subValue movzx eax,word ptr[bp+06h] ; move col into bx register, zero extended add addValue,eax ; now add the column number back in mov dx,word ptr addValue+02h ; move high word addValue to dx register mov ax,word ptr addValue ; move low word addValue to ax register add ax,word ptr bmData@@mlpSrcPtr ; add low word mlpSrcPtr to low word addValue adc dx,0000h ; add any carry to high word addValue (dx) shl dx,03h ; multiply dx register by 8 (segment magic) add dx,word ptr bmData@@mlpSrcPtr+02h ; now add in high word of mlpSrcData mov es,dx ; move segment into extra segment register mov di,ax ; move offset into destination index register xor ax,ax ; clear out ax register mov al,byte ptr es:[di] ; move byte value into al register jmp @@return ; jump over error return code @@error: ; error return label mov ax,0FF00h ; error places 0FFh in al register @@return: ; normal return label pop di ; restore destination index register pop es ; restore extra segment register pop dx ; restore dx register pop cx ; restore cx register pop bx ; restore bx register add sp,LocalLength ; adjust stack for local variable pop bp ; restore stack frame retn ; return near to caller _getSrcDataByte endp _setDstDataByte proc near ; void setDstDataByte(WORD row,WORD col,BYTE byteValue) LOCAL addValue:DWORD=LocalLength push bp ; save old stack frame mov bp,sp ; create new stack frame sub sp,LocalLength ; adjust stack for local variable push ax ; save ax register push bx ; save bx register push cx ; save cx register push dx ; save dx register push es ; save extra segment register push di ; save destination index register mov dx,word ptr[bp+04h] ; move row into dx register cmp dx,bmData@@mDstHeight ; is row greater than bitmap height jge @@error ; if so then return cmp dx,00h ; is row less than zero jl @@error ; if so then return error movzx ebx,word ptr[bp+06h] ; move col into bx register, zero extended cmp bx,bmData@@mDstWidth ; is col greater than bitmap width jge @@error ; if so then return cmp bx,00h ; is col less than zero jl @@error ; if so then return error movzx ecx,bmData@@mDstWidth ; move width into cx register mov ax,bmData@@mDstHeight ; move height into ax register push dx ; save dx register multiply ax,cx ; multiply width*height result to eax pop dx ; restore dx register mov addValue,eax ; store result to addValue multiply dx,cx ; multiply row*width result to eax add eax,ecx ; add (row*width)+width sub addValue,eax ; calculate addValue-subValue movzx eax,word ptr[bp+06h] ; move col into bx register, zero extended add addValue,eax ; now add the column number back in mov dx,word ptr addValue+02h ; move high word addValue to dx register mov ax,word ptr addValue ; move low word addValue to ax register add ax,word ptr bmData@@mlpDstPtr ; add low word mlpSrcPtr to low word addValue adc dx,0000h ; add any carry to high word addValue (dx) shl dx,03h ; multiply dx register by 8 (segment magic) add dx,word ptr bmData@@mlpDstPtr+02h ; now add in high word of mlpSrcData mov es,dx ; move segment into extra segment register mov di,ax ; move offset into destination index register mov ax,word ptr[bp+08h] ; move byteValue into ax register mov byte ptr es:[di],al ; move byte value into mlpDstPtr jmp @@return ; jump over error return code @@error: ; error return label mov ax,0FF00h ; error places 0FFh in al register jmp @@return ; return @@return: ; normal return label pop di ; restore destination index register pop es ; restore extra segment register pop dx ; restore dx register pop cx ; restore cx register pop bx ; restore bx register pop ax ; restore ax register add sp,LocalLength ; adjust stack for local variable pop bp ; restore stack frame retn ; return near to caller _setDstDataByte endp _putImageBits proc near ; void putImageBits(eax dstPoints,ebx srcPoints) mov cx,ax ; move low word eax to cx register shr eax,16 ; move high word eax to ax push ebx ; save ebx register push ax ; save high word on stack push cx ; save low word on stack call _getSrcDataByte ; get source data byte result is in al add sp,04h ; caller adjusts stack after return pop ebx ; restore ebx register cmp ah,0FFh ; check return code je @@return ; if al==0xFFh call failed push ax ; push data byte mov cx,bx ; move low word destination to cx register shr ebx,16 ; move high word destination to bx push bx ; save high word on stack push cx ; save low word on stack call _setDstDataByte ; set destination data byte add sp,06h ; caller adjusts stack after return @@return: ; return label retn ; return near to caller _putImageBits endp _setSrcBitmapInfo proc far ; void setSrcBitmapInfo(WORD width,WORD height,UHUGE *lpBitmapImage) push bp ; save old stack frame mov bp,sp ; create new stack frame push dword ptr[bp+0Ah] ; push lpBitmapImage onto stack pop bmData@@mlpSrcPtr ; resore into mlpSrcPtr push word ptr[bp+08h] ; push srcBitmapHeight onto stack pop bmData@@mSrcHeight ; restore into mSrcHeight push word ptr[bp+06h] ; push srcBitmapWidth pop bmData@@mSrcWidth ; restore into mSrcWidth pop bp ; restore old stack frame retf ; return far to caller _setSrcBitmapInfo endp _setDstBitmapInfo proc far ; void setSrcBitmapInfo(WORD width,WORD height,UHUGE *lpBitmapImage) push bp ; save old stack frame mov bp,sp ; create new stack frame push dword ptr[bp+0Ah] ; push lpBitmapImage onto stack pop bmData@@mlpDstPtr ; resore into mlpSrcPtr push word ptr[bp+08h] ; push srcBitmapHeight onto stack pop bmData@@mDstHeight ; restore into mSrcHeight push word ptr[bp+06h] ; push srcBitmapWidth pop bmData@@mDstWidth ; restore into mSrcWidth pop bp ; restore old stack frame retf ; return far to caller _setDstBitmapInfo endp public _initEdge public _mapTexture public _setSrcBitmapInfo public _setDstBitmapInfo end