1
0
Fork 0
forked from fte/fteqw

Initial checkin of software rendering bits and bobs.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@20 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2004-08-23 03:03:41 +00:00
parent 3a7c75319a
commit fffb8897b9
55 changed files with 38138 additions and 0 deletions

1074
engine/sw/adivtab.h Normal file

File diff suppressed because it is too large Load diff

154
engine/sw/asm_draw.h Normal file
View file

@ -0,0 +1,154 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// asm_draw.h
//
// Include file for asm drawing routines.
//
//
// !!! note that this file must match the corresponding C structures at all
// times !!!
//
// !!! if this is changed, it must be changed in r_local.h too !!!
#define NEAR_CLIP 0.01
// !!! if this is changed, it must be changed in r_local.h too !!!
#define CYCLE 128
// espan_t structure
// !!! if this is changed, it must be changed in r_shared.h too !!!
#define espan_t_u 0
#define espan_t_v 4
#define espan_t_count 8
#define espan_t_pnext 12
#define espan_t_size 16
// sspan_t structure
// !!! if this is changed, it must be changed in d_local.h too !!!
#define sspan_t_u 0
#define sspan_t_v 4
#define sspan_t_count 8
#define sspan_t_size 12
// spanpackage_t structure
// !!! if this is changed, it must be changed in d_polyset.c too !!!
#define spanpackage_t_pdest 0
#define spanpackage_t_pz 4
#define spanpackage_t_count 8
#define spanpackage_t_ptex 12
#define spanpackage_t_sfrac 16
#define spanpackage_t_tfrac 20
#define spanpackage_t_light 24
#define spanpackage_t_zi 28
#define spanpackage_t_size 32
// edge_t structure
// !!! if this is changed, it must be changed in r_shared.h too !!!
#define et_u 0
#define et_u_step 4
#define et_prev 8
#define et_next 12
#define et_surfs 16
#define et_nextremove 20
#define et_nearzi 24
#define et_owner 28
#define et_size 32
// surf_t structure
// !!! if this is changed, it must be changed in r_shared.h too !!!
#define SURF_T_SHIFT 6
#define st_next 0
#define st_prev 4
#define st_spans 8
#define st_key 12
#define st_last_u 16
#define st_spanstate 20
#define st_flags 24
#define st_data 28
#define st_entity 32
#define st_nearzi 36
#define st_insubmodel 40
#define st_d_ziorigin 44
#define st_d_zistepu 48
#define st_d_zistepv 52
#define st_pad 56
#define st_size 64
// clipplane_t structure
// !!! if this is changed, it must be changed in r_local.h too !!!
#define cp_normal 0
#define cp_dist 12
#define cp_next 16
#define cp_leftedge 20
#define cp_rightedge 21
#define cp_reserved 22
#define cp_size 24
// medge_t structure
// !!! if this is changed, it must be changed in model.h too !!!
#define me_v 0
#define me_cachededgeoffset 4
#define me_size 8
// mvertex_t structure
// !!! if this is changed, it must be changed in model.h too !!!
#define mv_position 0
#define mv_size 12
// refdef_t structure
// !!! if this is changed, it must be changed in render.h too !!!
#define rd_vrect 0
#define rd_aliasvrect 20
#define rd_vrectright 40
#define rd_vrectbottom 44
#define rd_aliasvrectright 48
#define rd_aliasvrectbottom 52
#define rd_vrectrightedge 56
#define rd_fvrectx 60
#define rd_fvrecty 64
#define rd_fvrectx_adj 68
#define rd_fvrecty_adj 72
#define rd_vrect_x_adj_shift20 76
#define rd_vrectright_adj_shift20 80
#define rd_fvrectright_adj 84
#define rd_fvrectbottom_adj 88
#define rd_fvrectright 92
#define rd_fvrectbottom 96
#define rd_horizontalFieldOfView 100
#define rd_xOrigin 104
#define rd_yOrigin 108
#define rd_vieworg 112
#define rd_viewangles 124
#define rd_ambientlight 136
#define rd_flags 140
#define rd_currentplayernum 144
#define rd_size 148
// mtriangle_t structure
// !!! if this is changed, it must be changed in model.h too !!!
#define mtri_facesfront 0
#define mtri_vertindex 4
#define mtri_stindex 16
#define mtri_size 28 // !!! if this changes, array indexing in !!!
// !!! d_polysa.s must be changed to match !!!
#define mtri_shift 4

123
engine/sw/block16.h Normal file
View file

@ -0,0 +1,123 @@
LEnter16_16:
movb (%esi),%al
movb (%esi,%ebx,),%cl
movb %dh,%ah
addl %ebp,%edx
movb %dh,%ch
leal (%esi,%ebx,2),%esi
movw 0x12345678(,%eax,2),%ax
LBPatch0:
addl %ebp,%edx
movw %ax,(%edi)
movw 0x12345678(,%ecx,2),%cx
LBPatch1:
movw %cx,2(%edi)
addl $0x4,%edi
movb (%esi),%al
movb (%esi,%ebx,),%cl
movb %dh,%ah
addl %ebp,%edx
movb %dh,%ch
leal (%esi,%ebx,2),%esi
movw 0x12345678(,%eax,2),%ax
LBPatch2:
addl %ebp,%edx
movw %ax,(%edi)
movw 0x12345678(,%ecx,2),%cx
LBPatch3:
movw %cx,2(%edi)
addl $0x4,%edi
movb (%esi),%al
movb (%esi,%ebx,),%cl
movb %dh,%ah
addl %ebp,%edx
movb %dh,%ch
leal (%esi,%ebx,2),%esi
movw 0x12345678(,%eax,2),%ax
LBPatch4:
addl %ebp,%edx
movw %ax,(%edi)
movw 0x12345678(,%ecx,2),%cx
LBPatch5:
movw %cx,2(%edi)
addl $0x4,%edi
movb (%esi),%al
movb (%esi,%ebx,),%cl
movb %dh,%ah
addl %ebp,%edx
movb %dh,%ch
leal (%esi,%ebx,2),%esi
movw 0x12345678(,%eax,2),%ax
LBPatch6:
addl %ebp,%edx
movw %ax,(%edi)
movw 0x12345678(,%ecx,2),%cx
LBPatch7:
movw %cx,2(%edi)
addl $0x4,%edi
LEnter8_16:
movb (%esi),%al
movb (%esi,%ebx,),%cl
movb %dh,%ah
addl %ebp,%edx
movb %dh,%ch
leal (%esi,%ebx,2),%esi
movw 0x12345678(,%eax,2),%ax
LBPatch8:
addl %ebp,%edx
movw %ax,(%edi)
movw 0x12345678(,%ecx,2),%cx
LBPatch9:
movw %cx,2(%edi)
addl $0x4,%edi
movb (%esi),%al
movb (%esi,%ebx,),%cl
movb %dh,%ah
addl %ebp,%edx
movb %dh,%ch
leal (%esi,%ebx,2),%esi
movw 0x12345678(,%eax,2),%ax
LBPatch10:
addl %ebp,%edx
movw %ax,(%edi)
movw 0x12345678(,%ecx,2),%cx
LBPatch11:
movw %cx,2(%edi)
addl $0x4,%edi
LEnter4_16:
movb (%esi),%al
movb (%esi,%ebx,),%cl
movb %dh,%ah
addl %ebp,%edx
movb %dh,%ch
leal (%esi,%ebx,2),%esi
movw 0x12345678(,%eax,2),%ax
LBPatch12:
addl %ebp,%edx
movw %ax,(%edi)
movw 0x12345678(,%ecx,2),%cx
LBPatch13:
movw %cx,2(%edi)
addl $0x4,%edi
LEnter2_16:
movb (%esi),%al
movb (%esi,%ebx,),%cl
movb %dh,%ah
addl %ebp,%edx
movb %dh,%ch
leal (%esi,%ebx,2),%esi
movw 0x12345678(,%eax,2),%ax
LBPatch14:
addl %ebp,%edx
movw %ax,(%edi)
movw 0x12345678(,%ecx,2),%cx
LBPatch15:
movw %cx,2(%edi)
addl $0x4,%edi

1037
engine/sw/d_draw.s Normal file

File diff suppressed because it is too large Load diff

974
engine/sw/d_draw16.s Normal file
View file

@ -0,0 +1,974 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// d_draw16.s
// x86 assembly-language horizontal 16-bpp span-drawing code, with 16-pixel
// subdivision.
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"
#if id386
//----------------------------------------------------------------------
// 8-bpp horizontal span drawing code for polygons, with no transparency and
// 16-pixel subdivision.
//
// Assumes there is at least one span in pspans, and that every span
// contains at least one pixel
//----------------------------------------------------------------------
.data
.text
// out-of-line, rarely-needed clamping code
LClampHigh0:
movl C(bbextents),%esi
jmp LClampReentry0
LClampHighOrLow0:
jg LClampHigh0
xorl %esi,%esi
jmp LClampReentry0
LClampHigh1:
movl C(bbextentt),%edx
jmp LClampReentry1
LClampHighOrLow1:
jg LClampHigh1
xorl %edx,%edx
jmp LClampReentry1
LClampLow2:
movl $4096,%ebp
jmp LClampReentry2
LClampHigh2:
movl C(bbextents),%ebp
jmp LClampReentry2
LClampLow3:
movl $4096,%ecx
jmp LClampReentry3
LClampHigh3:
movl C(bbextentt),%ecx
jmp LClampReentry3
LClampLow4:
movl $4096,%eax
jmp LClampReentry4
LClampHigh4:
movl C(bbextents),%eax
jmp LClampReentry4
LClampLow5:
movl $4096,%ebx
jmp LClampReentry5
LClampHigh5:
movl C(bbextentt),%ebx
jmp LClampReentry5
#define pspans 4+16
.align 4
.globl C(D_DrawSpans8SubDiv16)
C(D_DrawSpans8SubDiv16):
pushl %ebp // preserve caller's stack frame
pushl %edi
pushl %esi // preserve register variables
pushl %ebx
//
// set up scaled-by-16 steps, for 16-long segments; also set up cacheblock
// and span list pointers
//
// TODO: any overlap from rearranging?
flds C(d_sdivzstepu)
fmuls fp_16
movl C(cacheblock),%edx
flds C(d_tdivzstepu)
fmuls fp_16
movl pspans(%esp),%ebx // point to the first span descriptor
flds C(d_zistepu)
fmuls fp_16
movl %edx,pbase // pbase = cacheblock
fstps zi16stepu
fstps tdivz16stepu
fstps sdivz16stepu
LSpanLoop:
//
// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the
// initial s and t values
//
// FIXME: pipeline FILD?
fildl espan_t_v(%ebx)
fildl espan_t_u(%ebx)
fld %st(1) // dv | du | dv
fmuls C(d_sdivzstepv) // dv*d_sdivzstepv | du | dv
fld %st(1) // du | dv*d_sdivzstepv | du | dv
fmuls C(d_sdivzstepu) // du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
fld %st(2) // du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
fmuls C(d_tdivzstepu) // du*d_tdivzstepu | du*d_sdivzstepu |
// dv*d_sdivzstepv | du | dv
fxch %st(1) // du*d_sdivzstepu | du*d_tdivzstepu |
// dv*d_sdivzstepv | du | dv
faddp %st(0),%st(2) // du*d_tdivzstepu |
// du*d_sdivzstepu + dv*d_sdivzstepv | du | dv
fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv |
// du*d_tdivzstepu | du | dv
fld %st(3) // dv | du*d_sdivzstepu + dv*d_sdivzstepv |
// du*d_tdivzstepu | du | dv
fmuls C(d_tdivzstepv) // dv*d_tdivzstepv |
// du*d_sdivzstepu + dv*d_sdivzstepv |
// du*d_tdivzstepu | du | dv
fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv |
// dv*d_tdivzstepv | du*d_tdivzstepu | du | dv
fadds C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv +
// du*d_sdivzstepu; stays in %st(2) at end
fxch %st(4) // dv | dv*d_tdivzstepv | du*d_tdivzstepu | du |
// s/z
fmuls C(d_zistepv) // dv*d_zistepv | dv*d_tdivzstepv |
// du*d_tdivzstepu | du | s/z
fxch %st(1) // dv*d_tdivzstepv | dv*d_zistepv |
// du*d_tdivzstepu | du | s/z
faddp %st(0),%st(2) // dv*d_zistepv |
// dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z
fxch %st(2) // du | dv*d_tdivzstepv + du*d_tdivzstepu |
// dv*d_zistepv | s/z
fmuls C(d_zistepu) // du*d_zistepu |
// dv*d_tdivzstepv + du*d_tdivzstepu |
// dv*d_zistepv | s/z
fxch %st(1) // dv*d_tdivzstepv + du*d_tdivzstepu |
// du*d_zistepu | dv*d_zistepv | s/z
fadds C(d_tdivzorigin) // tdivz = d_tdivzorigin + dv*d_tdivzstepv +
// du*d_tdivzstepu; stays in %st(1) at end
fxch %st(2) // dv*d_zistepv | du*d_zistepu | t/z | s/z
faddp %st(0),%st(1) // dv*d_zistepv + du*d_zistepu | t/z | s/z
flds fp_64k // fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z
fxch %st(1) // dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z
fadds C(d_ziorigin) // zi = d_ziorigin + dv*d_zistepv +
// du*d_zistepu; stays in %st(0) at end
// 1/z | fp_64k | t/z | s/z
//
// calculate and clamp s & t
//
fdivr %st(0),%st(1) // 1/z | z*64k | t/z | s/z
//
// point %edi to the first pixel in the span
//
movl C(d_viewbuffer),%ecx
movl espan_t_v(%ebx),%eax
movl %ebx,pspantemp // preserve spans pointer
movl C(tadjust),%edx
movl C(sadjust),%esi
movl C(d_scantable)(,%eax,4),%edi // v * screenwidth
addl %ecx,%edi
movl espan_t_u(%ebx),%ecx
addl %ecx,%edi // pdest = &pdestspan[scans->u];
movl espan_t_count(%ebx),%ecx
//
// now start the FDIV for the end of the span
//
cmpl $16,%ecx
ja LSetupNotLast1
decl %ecx
jz LCleanup1 // if only one pixel, no need to start an FDIV
movl %ecx,spancountminus1
// finish up the s and t calcs
fxch %st(1) // z*64k | 1/z | t/z | s/z
fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z
fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z
fxch %st(1) // z*64k | s | 1/z | t/z | s/z
fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z
fxch %st(1) // s | t | 1/z | t/z | s/z
fistpl s // 1/z | t | t/z | s/z
fistpl t // 1/z | t/z | s/z
fildl spancountminus1
flds C(d_tdivzstepu) // C(d_tdivzstepu) | spancountminus1
flds C(d_zistepu) // C(d_zistepu) | C(d_tdivzstepu) | spancountminus1
fmul %st(2),%st(0) // C(d_zistepu)*scm1 | C(d_tdivzstepu) | scm1
fxch %st(1) // C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1
fmul %st(2),%st(0) // C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1
fxch %st(2) // scm1 | C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1
fmuls C(d_sdivzstepu) // C(d_sdivzstepu)*scm1 | C(d_zistepu)*scm1 |
// C(d_tdivzstepu)*scm1
fxch %st(1) // C(d_zistepu)*scm1 | C(d_sdivzstepu)*scm1 |
// C(d_tdivzstepu)*scm1
faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1
fxch %st(1) // C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1
faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1
faddp %st(0),%st(3)
flds fp_64k
fdiv %st(1),%st(0) // this is what we've gone to all this trouble to
// overlap
jmp LFDIVInFlight1
LCleanup1:
// finish up the s and t calcs
fxch %st(1) // z*64k | 1/z | t/z | s/z
fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z
fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z
fxch %st(1) // z*64k | s | 1/z | t/z | s/z
fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z
fxch %st(1) // s | t | 1/z | t/z | s/z
fistpl s // 1/z | t | t/z | s/z
fistpl t // 1/z | t/z | s/z
jmp LFDIVInFlight1
.align 4
LSetupNotLast1:
// finish up the s and t calcs
fxch %st(1) // z*64k | 1/z | t/z | s/z
fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z
fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z
fxch %st(1) // z*64k | s | 1/z | t/z | s/z
fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z
fxch %st(1) // s | t | 1/z | t/z | s/z
fistpl s // 1/z | t | t/z | s/z
fistpl t // 1/z | t/z | s/z
fadds zi16stepu
fxch %st(2)
fadds sdivz16stepu
fxch %st(2)
flds tdivz16stepu
faddp %st(0),%st(2)
flds fp_64k
fdiv %st(1),%st(0) // z = 1/1/z
// this is what we've gone to all this trouble to
// overlap
LFDIVInFlight1:
addl s,%esi
addl t,%edx
movl C(bbextents),%ebx
movl C(bbextentt),%ebp
cmpl %ebx,%esi
ja LClampHighOrLow0
LClampReentry0:
movl %esi,s
movl pbase,%ebx
shll $16,%esi
cmpl %ebp,%edx
movl %esi,sfracf
ja LClampHighOrLow1
LClampReentry1:
movl %edx,t
movl s,%esi // sfrac = scans->sfrac;
shll $16,%edx
movl t,%eax // tfrac = scans->tfrac;
sarl $16,%esi
movl %edx,tfracf
//
// calculate the texture starting address
//
sarl $16,%eax
movl C(cachewidth),%edx
imull %edx,%eax // (tfrac >> 16) * cachewidth
addl %ebx,%esi
addl %eax,%esi // psource = pbase + (sfrac >> 16) +
// ((tfrac >> 16) * cachewidth);
//
// determine whether last span or not
//
cmpl $16,%ecx
jna LLastSegment
//
// not the last segment; do full 16-wide segment
//
LNotLastSegment:
//
// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
// get there
//
// pick up after the FDIV that was left in flight previously
fld %st(0) // duplicate it
fmul %st(4),%st(0) // s = s/z * z
fxch %st(1)
fmul %st(3),%st(0) // t = t/z * z
fxch %st(1)
fistpl snext
fistpl tnext
movl snext,%eax
movl tnext,%edx
movb (%esi),%bl // get first source texel
subl $16,%ecx // count off this segments' pixels
movl C(sadjust),%ebp
movl %ecx,counttemp // remember count of remaining pixels
movl C(tadjust),%ecx
movb %bl,(%edi) // store first dest pixel
addl %eax,%ebp
addl %edx,%ecx
movl C(bbextents),%eax
movl C(bbextentt),%edx
cmpl $4096,%ebp
jl LClampLow2
cmpl %eax,%ebp
ja LClampHigh2
LClampReentry2:
cmpl $4096,%ecx
jl LClampLow3
cmpl %edx,%ecx
ja LClampHigh3
LClampReentry3:
movl %ebp,snext
movl %ecx,tnext
subl s,%ebp
subl t,%ecx
//
// set up advancetable
//
movl %ecx,%eax
movl %ebp,%edx
sarl $20,%eax // tstep >>= 16;
jz LZero
sarl $20,%edx // sstep >>= 16;
movl C(cachewidth),%ebx
imull %ebx,%eax
jmp LSetUp1
LZero:
sarl $20,%edx // sstep >>= 16;
movl C(cachewidth),%ebx
LSetUp1:
addl %edx,%eax // add in sstep
// (tstep >> 16) * cachewidth + (sstep >> 16);
movl tfracf,%edx
movl %eax,advancetable+4 // advance base in t
addl %ebx,%eax // ((tstep >> 16) + 1) * cachewidth +
// (sstep >> 16);
shll $12,%ebp // left-justify sstep fractional part
movl sfracf,%ebx
shll $12,%ecx // left-justify tstep fractional part
movl %eax,advancetable // advance extra in t
movl %ecx,tstep
addl %ecx,%edx // advance tfrac fractional part by tstep frac
sbbl %ecx,%ecx // turn tstep carry into -1 (0 if none)
addl %ebp,%ebx // advance sfrac fractional part by sstep frac
adcl advancetable+4(,%ecx,4),%esi // point to next source texel
addl tstep,%edx
sbbl %ecx,%ecx
movb (%esi),%al
addl %ebp,%ebx
movb %al,1(%edi)
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,2(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,3(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,4(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,5(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,6(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,7(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
//
// start FDIV for end of next segment in flight, so it can overlap
//
movl counttemp,%ecx
cmpl $16,%ecx // more than one segment after this?
ja LSetupNotLast2 // yes
decl %ecx
jz LFDIVInFlight2 // if only one pixel, no need to start an FDIV
movl %ecx,spancountminus1
fildl spancountminus1
flds C(d_zistepu) // C(d_zistepu) | spancountminus1
fmul %st(1),%st(0) // C(d_zistepu)*scm1 | scm1
flds C(d_tdivzstepu) // C(d_tdivzstepu) | C(d_zistepu)*scm1 | scm1
fmul %st(2),%st(0) // C(d_tdivzstepu)*scm1 | C(d_zistepu)*scm1 | scm1
fxch %st(1) // C(d_zistepu)*scm1 | C(d_tdivzstepu)*scm1 | scm1
faddp %st(0),%st(3) // C(d_tdivzstepu)*scm1 | scm1
fxch %st(1) // scm1 | C(d_tdivzstepu)*scm1
fmuls C(d_sdivzstepu) // C(d_sdivzstepu)*scm1 | C(d_tdivzstepu)*scm1
fxch %st(1) // C(d_tdivzstepu)*scm1 | C(d_sdivzstepu)*scm1
faddp %st(0),%st(3) // C(d_sdivzstepu)*scm1
flds fp_64k // 64k | C(d_sdivzstepu)*scm1
fxch %st(1) // C(d_sdivzstepu)*scm1 | 64k
faddp %st(0),%st(4) // 64k
fdiv %st(1),%st(0) // this is what we've gone to all this trouble to
// overlap
jmp LFDIVInFlight2
.align 4
LSetupNotLast2:
fadds zi16stepu
fxch %st(2)
fadds sdivz16stepu
fxch %st(2)
flds tdivz16stepu
faddp %st(0),%st(2)
flds fp_64k
fdiv %st(1),%st(0) // z = 1/1/z
// this is what we've gone to all this trouble to
// overlap
LFDIVInFlight2:
movl %ecx,counttemp
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,8(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,9(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,10(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,11(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,12(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,13(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,14(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl $16,%edi
movl %edx,tfracf
movl snext,%edx
movl %ebx,sfracf
movl tnext,%ebx
movl %edx,s
movl %ebx,t
movl counttemp,%ecx // retrieve count
//
// determine whether last span or not
//
cmpl $16,%ecx // are there multiple segments remaining?
movb %al,-1(%edi)
ja LNotLastSegment // yes
//
// last segment of scan
//
LLastSegment:
//
// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
// get there. The number of pixels left is variable, and we want to land on the
// last pixel, not step one past it, so we can't run into arithmetic problems
//
testl %ecx,%ecx
jz LNoSteps // just draw the last pixel and we're done
// pick up after the FDIV that was left in flight previously
fld %st(0) // duplicate it
fmul %st(4),%st(0) // s = s/z * z
fxch %st(1)
fmul %st(3),%st(0) // t = t/z * z
fxch %st(1)
fistpl snext
fistpl tnext
movb (%esi),%al // load first texel in segment
movl C(tadjust),%ebx
movb %al,(%edi) // store first pixel in segment
movl C(sadjust),%eax
addl snext,%eax
addl tnext,%ebx
movl C(bbextents),%ebp
movl C(bbextentt),%edx
cmpl $4096,%eax
jl LClampLow4
cmpl %ebp,%eax
ja LClampHigh4
LClampReentry4:
movl %eax,snext
cmpl $4096,%ebx
jl LClampLow5
cmpl %edx,%ebx
ja LClampHigh5
LClampReentry5:
cmpl $1,%ecx // don't bother
je LOnlyOneStep // if two pixels in segment, there's only one step,
// of the segment length
subl s,%eax
subl t,%ebx
addl %eax,%eax // convert to 15.17 format so multiply by 1.31
addl %ebx,%ebx // reciprocal yields 16.48
imull reciprocal_table_16-8(,%ecx,4) // sstep = (snext - s) /
// (spancount-1)
movl %edx,%ebp
movl %ebx,%eax
imull reciprocal_table_16-8(,%ecx,4) // tstep = (tnext - t) /
// (spancount-1)
LSetEntryvec:
//
// set up advancetable
//
movl entryvec_table_16(,%ecx,4),%ebx
movl %edx,%eax
movl %ebx,jumptemp // entry point into code for RET later
movl %ebp,%ecx
sarl $16,%edx // tstep >>= 16;
movl C(cachewidth),%ebx
sarl $16,%ecx // sstep >>= 16;
imull %ebx,%edx
addl %ecx,%edx // add in sstep
// (tstep >> 16) * cachewidth + (sstep >> 16);
movl tfracf,%ecx
movl %edx,advancetable+4 // advance base in t
addl %ebx,%edx // ((tstep >> 16) + 1) * cachewidth +
// (sstep >> 16);
shll $16,%ebp // left-justify sstep fractional part
movl sfracf,%ebx
shll $16,%eax // left-justify tstep fractional part
movl %edx,advancetable // advance extra in t
movl %eax,tstep
movl %ecx,%edx
addl %eax,%edx
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
jmp *jumptemp // jump to the number-of-pixels handler
//----------------------------------------
LNoSteps:
movb (%esi),%al // load first texel in segment
subl $15,%edi // adjust for hardwired offset
jmp LEndSpan
LOnlyOneStep:
subl s,%eax
subl t,%ebx
movl %eax,%ebp
movl %ebx,%edx
jmp LSetEntryvec
//----------------------------------------
.globl Entry2_16, Entry3_16, Entry4_16, Entry5_16
.globl Entry6_16, Entry7_16, Entry8_16, Entry9_16
.globl Entry10_16, Entry11_16, Entry12_16, Entry13_16
.globl Entry14_16, Entry15_16, Entry16_16
Entry2_16:
subl $14,%edi // adjust for hardwired offsets
movb (%esi),%al
jmp LEntry2_16
//----------------------------------------
Entry3_16:
subl $13,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
jmp LEntry3_16
//----------------------------------------
Entry4_16:
subl $12,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry4_16
//----------------------------------------
Entry5_16:
subl $11,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry5_16
//----------------------------------------
Entry6_16:
subl $10,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry6_16
//----------------------------------------
Entry7_16:
subl $9,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry7_16
//----------------------------------------
Entry8_16:
subl $8,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry8_16
//----------------------------------------
Entry9_16:
subl $7,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry9_16
//----------------------------------------
Entry10_16:
subl $6,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry10_16
//----------------------------------------
Entry11_16:
subl $5,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry11_16
//----------------------------------------
Entry12_16:
subl $4,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry12_16
//----------------------------------------
Entry13_16:
subl $3,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry13_16
//----------------------------------------
Entry14_16:
subl $2,%edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry14_16
//----------------------------------------
Entry15_16:
decl %edi // adjust for hardwired offsets
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
jmp LEntry15_16
//----------------------------------------
Entry16_16:
addl %eax,%edx
movb (%esi),%al
sbbl %ecx,%ecx
addl %ebp,%ebx
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
sbbl %ecx,%ecx
movb %al,1(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry15_16:
sbbl %ecx,%ecx
movb %al,2(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry14_16:
sbbl %ecx,%ecx
movb %al,3(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry13_16:
sbbl %ecx,%ecx
movb %al,4(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry12_16:
sbbl %ecx,%ecx
movb %al,5(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry11_16:
sbbl %ecx,%ecx
movb %al,6(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry10_16:
sbbl %ecx,%ecx
movb %al,7(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry9_16:
sbbl %ecx,%ecx
movb %al,8(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry8_16:
sbbl %ecx,%ecx
movb %al,9(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry7_16:
sbbl %ecx,%ecx
movb %al,10(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry6_16:
sbbl %ecx,%ecx
movb %al,11(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry5_16:
sbbl %ecx,%ecx
movb %al,12(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
addl tstep,%edx
LEntry4_16:
sbbl %ecx,%ecx
movb %al,13(%edi)
addl %ebp,%ebx
movb (%esi),%al
adcl advancetable+4(,%ecx,4),%esi
LEntry3_16:
movb %al,14(%edi)
movb (%esi),%al
LEntry2_16:
LEndSpan:
//
// clear s/z, t/z, 1/z from FP stack
//
fstp %st(0)
fstp %st(0)
fstp %st(0)
movl pspantemp,%ebx // restore spans pointer
movl espan_t_pnext(%ebx),%ebx // point to next span
testl %ebx,%ebx // any more spans?
movb %al,15(%edi)
jnz LSpanLoop // more spans
popl %ebx // restore register variables
popl %esi
popl %edi
popl %ebp // restore the caller's stack frame
ret
#endif // id386

435
engine/sw/d_edge.c Normal file
View file

@ -0,0 +1,435 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_edge.c
#include "quakedef.h"
#include "d_local.h"
static int miplevel;
float scale_for_mip;
int screenwidth;
int ubasestep, errorterm, erroradjustup, erroradjustdown;
int vstartscan;
// FIXME: should go away
extern void R_RotateBmodel (void);
extern void R_TransformFrustum (void);
vec3_t transformed_modelorg;
/*
==============
D_DrawPoly
==============
*/
void D_DrawPoly (void)
{
// this driver takes spans, not polygons
}
/*
=============
D_MipLevelForScale
=============
*/
int D_MipLevelForScale (float scale)
{
int lmiplevel;
if (scale >= d_scalemip[0] )
lmiplevel = 0;
else if (scale >= d_scalemip[1] )
lmiplevel = 1;
else if (scale >= d_scalemip[2] )
lmiplevel = 2;
else
lmiplevel = 3;
if (lmiplevel < d_minmip)
lmiplevel = d_minmip;
return lmiplevel;
}
/*
==============
D_DrawSolidSurface
==============
*/
// FIXME: clean this up
void D_DrawSolidSurface (surf_t *surf, int color)
{
espan_t *span;
qbyte *pdest;
int u, u2, pix;
if (r_pixbytes == 4)
{
unsigned int *p32dest;
pix = d_8to32table[color];
for (span=surf->spans ; span ; span=span->pnext)
{
p32dest = (unsigned int *)d_viewbuffer + screenwidth*span->v;
u = span->u;
u2 = span->u + span->count - 1;
p32dest[u] = pix;
for ( ; u <= u2 ; u++)
p32dest[u] = pix;
}
}
else
{
pix = (color<<24) | (color<<16) | (color<<8) | color;
for (span=surf->spans ; span ; span=span->pnext)
{
pdest = (qbyte *)d_viewbuffer + screenwidth*span->v;
u = span->u;
u2 = span->u + span->count - 1;
((qbyte *)pdest)[u] = pix;
if (u2 - u < 8)
{
for (u++ ; u <= u2 ; u++)
((qbyte *)pdest)[u] = pix;
}
else
{
for (u++ ; u & 3 ; u++)
((qbyte *)pdest)[u] = pix;
u2 -= 3;
for ( ; u <= u2 ; u+=4)
*(int *)((qbyte *)pdest + u) = pix;
u2 += 3;
for ( ; u <= u2 ; u++)
((qbyte *)pdest)[u] = pix;
}
}
}
}
/*
==============
D_CalcGradients
==============
*/
void D_CalcGradients (msurface_t *pface)
{
mplane_t *pplane;
float mipscale;
vec3_t p_temp1;
vec3_t p_saxis, p_taxis;
float t;
pplane = pface->plane;
mipscale = 1.0 / (float)(1 << miplevel);
TransformVector (pface->texinfo->vecs[0], p_saxis);
TransformVector (pface->texinfo->vecs[1], p_taxis);
t = xscaleinv * mipscale;
d_sdivzstepu = p_saxis[0] * t;
d_tdivzstepu = p_taxis[0] * t;
t = yscaleinv * mipscale;
d_sdivzstepv = -p_saxis[1] * t;
d_tdivzstepv = -p_taxis[1] * t;
d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
ycenter * d_sdivzstepv;
d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
ycenter * d_tdivzstepv;
VectorScale (transformed_modelorg, mipscale, p_temp1);
t = 0x10000*mipscale;
sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
((pface->texturemins[0] << 16) >> miplevel)
+ pface->texinfo->vecs[0][3]*t;
tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
((pface->texturemins[1] << 16) >> miplevel)
+ pface->texinfo->vecs[1][3]*t;
//
// -1 (-epsilon) so we never wander off the edge of the texture
//
bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
}
/*
==============
D_DrawSurfaces
==============
*/
void D_DrawSurfaces (void)
{
void D_DrawSpans32 (espan_t *pspan);
surf_t *s;
msurface_t *pface;
surfcache_t *pcurrentcache;
vec3_t world_transformed_modelorg;
vec3_t local_modelorg;
extern int r_dosirds;
currententity = &r_worldentity;
TransformVector (modelorg, transformed_modelorg);
VectorCopy (transformed_modelorg, world_transformed_modelorg);
if (r_dosirds) //depth only
{
for (s = &surfaces[1] ; s<surface_p ; s++)
{
if (!s->spans)
continue;
d_zistepu = s->d_zistepu;
d_zistepv = s->d_zistepv;
d_ziorigin = s->d_ziorigin;
D_DrawZSpans (s->spans);
}
}
// TODO: could preset a lot of this at mode set time
else if (r_drawflat.value)
{
for (s = &surfaces[1] ; s<surface_p ; s++)
{
if (!s->spans)
continue;
d_zistepu = s->d_zistepu;
d_zistepv = s->d_zistepv;
d_ziorigin = s->d_ziorigin;
#ifdef __alpha__
D_DrawSolidSurface (s, (int)((long)s->data & 0xFF));
#else
D_DrawSolidSurface (s, (int)s->data & 0xFF);
#endif
D_DrawZSpans (s->spans);
}
}
else
{
for (s = &surfaces[1] ; s<surface_p ; s++)
{
if (!s->spans)
continue;
r_drawnpolycount++;
d_zistepu = s->d_zistepu;
d_zistepv = s->d_zistepv;
d_ziorigin = s->d_ziorigin;
if (s->flags & SURF_DRAWSKY)
{
if (r_worldentity.model->fromgame == fg_halflife)
continue;
if (!r_skymade)
{
R_MakeSky ();
}
if (r_pixbytes == 4)
D_DrawSkyScans32 (s->spans);
else if (r_pixbytes == 2)
D_DrawSkyScans16 (s->spans);
else
D_DrawSkyScans8 (s->spans);
D_DrawZSpans (s->spans);
}
else if (s->flags & SURF_DRAWSKYBOX)
{
pface = s->data;
miplevel = 0;
if (!pface->texinfo->texture)
{
d_zistepu = 0;
d_zistepv = 0;
d_ziorigin = -0.9;
D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF);
D_DrawZSpans (s->spans);
continue;
}
cacheblock = (qbyte *)pface->texinfo->texture + pface->texinfo->texture->offsets[0];
cachewidth = 256;
d_zistepu = s->d_zistepu;
d_zistepv = s->d_zistepv;
d_ziorigin = s->d_ziorigin;
D_CalcGradients (pface);
if (r_pixbytes == 2)
D_DrawSpans16From8(s->spans);
else
(*d_drawspans) (s->spans);
// D_DrawSolidSurface (s, (int)15);
// set up a gradient for the background surface that places it
// effectively at infinity distance from the viewpoint
d_zistepu = 0;
d_zistepv = 0;
d_ziorigin = -0.9;
D_DrawZSpans (s->spans);
}
else if (s->flags & SURF_DRAWBACKGROUND)
{
// set up a gradient for the background surface that places it
// effectively at infinity distance from the viewpoint
d_zistepu = 0;
d_zistepv = 0;
d_ziorigin = -0.9;
D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF);
D_DrawZSpans (s->spans);
}
else if (s->flags & SURF_DRAWTURB)
{
pface = s->data;
miplevel = 0;
cacheblock = (pixel_t *)
((qbyte *)pface->texinfo->texture +
pface->texinfo->texture->offsets[0]);
cachewidth = 64;
cacheheight = 64;
if (s->insubmodel)
{
// FIXME: we don't want to do all this for every polygon!
// TODO: store once at start of frame
currententity = s->entity; //FIXME: make this passed in to
// R_RotateBmodel ()
VectorSubtract (r_origin, currententity->origin,
local_modelorg);
TransformVector (local_modelorg, transformed_modelorg);
R_RotateBmodel (); // FIXME: don't mess with the frustum,
// make entity passed in
}
D_CalcGradients (pface);
if (r_pixbytes == 4)
Turbulent32 (s->spans);
else if (r_pixbytes == 2)
Turbulent16 (s->spans);
else
Turbulent8 (s->spans);
D_DrawZSpans (s->spans);
if (s->insubmodel)
{
//
// restore the old drawing state
// FIXME: we don't want to do this every time!
// TODO: speed up
//
currententity = &r_worldentity;
VectorCopy (world_transformed_modelorg,
transformed_modelorg);
VectorCopy (base_vpn, vpn);
VectorCopy (base_vup, vup);
VectorCopy (base_vright, vright);
VectorCopy (base_modelorg, modelorg);
R_TransformFrustum ();
}
}
else
{
if (s->insubmodel)
{
// FIXME: we don't want to do all this for every polygon!
// TODO: store once at start of frame
currententity = s->entity; //FIXME: make this passed in to
// R_RotateBmodel ()
VectorSubtract (r_origin, currententity->origin, local_modelorg);
TransformVector (local_modelorg, transformed_modelorg);
R_RotateBmodel (); // FIXME: don't mess with the frustum,
// make entity passed in
}
pface = s->data;
if (pface->flags & SURF_BULLETEN)
{
miplevel = 0;
if (pface->cachespots[miplevel])
pface->cachespots[miplevel]->texture = NULL;
}
else
{
miplevel = D_MipLevelForScale (s->nearzi * scale_for_mip
* pface->texinfo->mipadjust);
}
// FIXME: make this passed in to D_CacheSurface
pcurrentcache = D_CacheSurface (pface, miplevel);
cacheblock = (pixel_t *)pcurrentcache->data;
cachewidth = pcurrentcache->width;
cacheheight = pcurrentcache->height;
// if (s->entity == &r_worldentity) //temporary
// {
D_CalcGradients (pface);
(*d_drawspans) (s->spans);
if (d_drawspans != D_DrawSpans32)
D_DrawZSpans (s->spans);
// }
if (s->insubmodel)
{
//
// restore the old drawing state
// FIXME: we don't want to do this every time!
// TODO: speed up
//
VectorCopy (world_transformed_modelorg,
transformed_modelorg);
VectorCopy (base_vpn, vpn);
VectorCopy (base_vup, vup);
VectorCopy (base_vright, vright);
VectorCopy (base_modelorg, modelorg);
R_TransformFrustum ();
currententity = &r_worldentity;
}
}
}
}
}

88
engine/sw/d_fill.c Normal file
View file

@ -0,0 +1,88 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_clear: clears a specified rectangle to the specified color
#include "quakedef.h"
/*
================
D_FillRect
================
*/
void D_FillRect (vrect_t *rect, int color)
{
int rx, ry, rwidth, rheight;
unsigned char *dest;
unsigned *ldest;
rx = rect->x;
ry = rect->y;
rwidth = rect->width;
rheight = rect->height;
if (rx < 0)
{
rwidth += rx;
rx = 0;
}
if (ry < 0)
{
rheight += ry;
ry = 0;
}
if (rx+rwidth > vid.width)
rwidth = vid.width - rx;
if (ry+rheight > vid.height)
rheight = vid.height - rx;
if (rwidth < 1 || rheight < 1)
return;
dest = ((qbyte *)vid.buffer + ry*vid.rowbytes + rx);
if (((rwidth & 0x03) == 0) && (((long)dest & 0x03) == 0))
{
// faster aligned dword clear
ldest = (unsigned *)dest;
color += color << 16;
rwidth >>= 2;
color += color << 8;
for (ry=0 ; ry<rheight ; ry++)
{
for (rx=0 ; rx<rwidth ; rx++)
ldest[rx] = color;
ldest = (unsigned *)((qbyte*)ldest + vid.rowbytes);
}
}
else
{
// slower byte-by-byte clear for unaligned cases
for (ry=0 ; ry<rheight ; ry++)
{
for (rx=0 ; rx<rwidth ; rx++)
dest[rx] = color;
dest += vid.rowbytes;
}
}
}

226
engine/sw/d_iface.h Normal file
View file

@ -0,0 +1,226 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_iface.h: interface header file for rasterization driver modules
#define WARP_WIDTH 320
#define WARP_HEIGHT 200
#define MAX_LBM_HEIGHT 480
typedef struct
{
float u, v;
float s, t;
float zi;
} emitpoint_t;
#include "particles.h"
typedef struct polyvert_s {
float u, v, zi, s, t;
} polyvert_t;
typedef struct polydesc_s {
int numverts;
float nearzi;
msurface_t *pcurrentface;
polyvert_t *pverts;
} polydesc_t;
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
typedef struct finalvert_s {
int v[6]; // u, v, s, t, l, 1/z
int flags;
float reserved;
} finalvert_t;
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
typedef struct
{
void *pskin;
maliasskindesc_t *pskindesc;
int skinwidth;
int skinheight;
mtriangle_t *ptriangles;
finalvert_t *pfinalverts;
int numtriangles;
int drawtype;
mstvert_t *pstverts;
//int seamfixupX16;
} affinetridesc_t;
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
typedef struct {
float u, v, zi, color;
} screenpart_t;
typedef struct
{
int nump;
emitpoint_t *pverts; // there's room for an extra element at [nump],
// if the driver wants to duplicate element [0] at
// element [nump] to avoid dealing with wrapping
mspriteframe_t *pspriteframe;
vec3_t vup, vright, vpn; // in worldspace
float nearzi;
} spritedesc_t;
typedef struct
{
int u, v;
float zi;
int color;
} zpointdesc_t;
extern cvar_t r_drawflat;
extern int d_spanpixcount;
extern int r_framecount; // sequence # of current frame since Quake
// started
extern qboolean r_drawpolys; // 1 if driver wants clipped polygons
// rather than a span list
extern qboolean r_drawculledpolys; // 1 if driver wants clipped polygons that
// have been culled by the edge list
extern qboolean r_worldpolysbacktofront; // 1 if driver wants polygons
// delivered back to front rather
// than front to back
extern qboolean r_recursiveaffinetriangles; // true if a driver wants to use
// recursive triangular subdivison
// and vertex drawing via
// D_PolysetDrawFinalVerts() past
// a certain distance (normally
// only used by the software
// driver)
extern float r_aliasuvscale; // scale-up factor for screen u and v
// on Alias vertices passed to driver
//16 bit rendering.
extern int redbits, redshift;
extern int greenbits, greenshift;
extern int bluebits, blueshift;
extern int r_pixbytes;
extern qboolean r_dowarp;
extern affinetridesc_t r_affinetridesc;
extern spritedesc_t r_spritedesc;
extern zpointdesc_t r_zpointdesc;
extern polydesc_t r_polydesc;
extern int d_con_indirect; // if 0, Quake will draw console directly
// to vid.buffer; if 1, Quake will
// draw console via D_DrawRect. Must be
// defined by driver
extern vec3_t r_pright, r_pup, r_ppn;
void D_Aff8Patch (void *pcolormap);
void GLD_BeginDirectRect (int x, int y, qbyte *pbitmap, int width, int height);
void SWD_BeginDirectRect (int x, int y, qbyte *pbitmap, int width, int height);
void D_DisableBackBufferAccess (void);
void GLD_EndDirectRect (int x, int y, int width, int height);
void SWD_EndDirectRect (int x, int y, int width, int height);
void D_PolysetDraw (void);
void D_PolysetDraw16 (void);
void D_PolysetDraw32 (void);
void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts);
void D_PolysetDrawFinalVerts32Trans (finalvert_t *fv, int numverts);
void D_DrawParticle (particle_t *pparticle);
void D_DrawPoly (void);
void D_DrawSprite (void);
void D_DrawSurfaces (void);
void D_DrawZPoint (void);
void D_ClearDepth(void);
void D_EnableBackBufferAccess (void);
void D_EndParticles (void);
void D_Init (void);
void D_ViewChanged (void);
void D_SetupFrame (void);
void D_StartParticles (void);
void D_TurnZOn (void);
void D_WarpScreen (void);
void D_FillRect (vrect_t *vrect, int color);
void D_DrawRect (void);
void D_UpdateRects (vrect_t *prect);
// currently for internal use only, and should be a do-nothing function in
// hardware drivers
// FIXME: this should go away
void D_PolysetUpdateTables (void);
// these are currently for internal use only, and should not be used by drivers
extern int r_skydirect;
extern qbyte *r_skysource;
// transparency types for D_DrawRect ()
#define DR_SOLID 0
#define DR_TRANSPARENT 1
// !!! must be kept the same as in quakeasm.h !!!
#define TRANSPARENT_COLOR 0xFF
extern void *acolormap; // FIXME: should go away
//=======================================================================//
// callbacks to Quake
typedef struct
{
pixel_t *surfdat; // destination for generated surface
int rowbytes; // destination logical width in bytes
msurface_t *surf; // description for surface to generate
fixed8_t lightadj[MAXLIGHTMAPS];
// adjust for lightmap levels for dynamic lighting
texture_t *texture; // corrected for animating textures
int surfmip; // mipmapped ratio of surface texels / world pixels
int surfwidth; // in mipmapped texels
int surfheight; // in mipmapped texels
} drawsurf_t;
extern drawsurf_t r_drawsurf;
void R_DrawSurface (void);
void R_DrawSurface32 (void);
void R_GenTile (msurface_t *psurf, void *pdest);
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
#define TURB_TEX_SIZE 64 // base turbulent texture size
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
#define CYCLE 128 // turbulent cycle size
#define TILE_SIZE 128 // size of textures generated by R_GenTiledSurf
#define SKYSHIFT 7
#define SKYSIZE (1 << SKYSHIFT)
#define SKYMASK (SKYSIZE - 1)
extern float skyspeed, skyspeed2;
extern float skytime;
extern int c_surf;
extern vrect_t scr_vrect;
extern qbyte *r_warpbuffer;

97
engine/sw/d_ifacea.h Normal file
View file

@ -0,0 +1,97 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// d_ifacea.h
//
// Include file for asm driver interface.
//
//
// !!! note that this file must match the corresponding C structures in
// d_iface.h at all times !!!
//
// !!! if this is changed, it must be changed in r_shared.h too !!!
//#define ALIAS_ONSEAM 0x0020
// !!! if this is changed, it must be changed in d_iface.h too !!!
#define TURB_TEX_SIZE 64 // base turbulent texture size
// !!! if this is changed, it must be changed in d_iface.h too !!!
#define CYCLE 128
// !!! if this is changed, it must be changed in r_shared.h too !!!
#define MAXHEIGHT 1024
// !!! if this is changed, it must be changed in quakedef.h too !!!
#define CACHE_SIZE 32 // used to align key data structures
// particle_t structure
// !!! if this is changed, it must be changed in d_iface.h too !!!
// driver-usable fields
#define pt_org 0
#define pt_color 12
// drivers never touch the following fields
#define pt_next 16
#define pt_vel 20
#define pt_ramp 32
#define pt_die 36
#define pt_type 40
#define pt_size 44
#define PARTICLE_Z_CLIP 8.0
// finalvert_t structure
// !!! if this is changed, it must be changed in d_iface.h too !!!
#define fv_v 0 // !!! if this is moved, cases where the !!!
// !!! address of this field is pushed in !!!
// !!! d_polysa.s must be changed !!!
#define fv_flags 24
#define fv_reserved 28
#define fv_size 32
#define fv_shift 5
// stvert_t structure
// !!! if this is changed, it must be changed in modelgen.h too !!!
#define stv_s 4
#define stv_t 8
#define stv_size 12
// trivertx_t structure
// !!! if this is changed, it must be changed in modelgen.h too !!!
#define tv_v 0
#define tv_lightnormalindex 3
#define tv_size 4
// affinetridesc_t structure
// !!! if this is changed, it must be changed in d_iface.h too !!!
#define atd_pskin 0
#define atd_pskindesc 4
#define atd_skinwidth 8
#define atd_skinheight 12
#define atd_ptriangles 16
#define atd_pfinalverts 20
#define atd_numtriangles 24
#define atd_drawtype 28
#define atd_seamfixupX16 32
#define atd_size 36

198
engine/sw/d_init.c Normal file
View file

@ -0,0 +1,198 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_init.c: rasterization driver initialization
#include "quakedef.h"
#include "d_local.h"
#define NUM_MIPS 4
cvar_t d_subdiv16 = {"d_subdiv16", "1"};
cvar_t d_mipcap = {"d_mipcap", "0"};
cvar_t d_mipscale = {"d_mipscale", "0.5"};
extern cvar_t d_smooth;
surfcache_t *d_initial_rover;
qboolean d_roverwrapped;
int d_minmip;
float d_scalemip[NUM_MIPS-1];
static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
extern int d_aflatcolor;
void (*d_drawspans) (espan_t *pspan);
void D_DrawSpans32 (espan_t *pspan);
void D_DrawSpans32From8 (espan_t *pspan);
void D_DrawSpans32_Smooth (espan_t *pspan);
/*
===============
D_Init
===============
*/
void D_Init (void)
{
r_skydirect = 1;
r_drawpolys = false;
r_worldpolysbacktofront = false;
r_recursiveaffinetriangles = true;
if (!r_pixbytes)
r_pixbytes = 1;
r_aliasuvscale = 1.0;
#ifdef PEXT_TRANS
D_InitTrans();
#endif
}
/*
===============
D_CopyRects
===============
*/
void D_CopyRects (vrect_t *prects, int transparent)
{
// this function is only required if the CPU doesn't have direct access to the
// back buffer, and there's some driver interface function that the driver
// doesn't support and requires Quake to do in software (such as drawing the
// console); Quake will then draw into wherever the driver points vid.buffer
// and will call this function before swapping buffers
UNUSED(prects);
UNUSED(transparent);
}
/*
===============
D_EnableBackBufferAccess
===============
*/
void D_EnableBackBufferAccess (void)
{
VID_LockBuffer ();
}
/*
===============
D_TurnZOn
===============
*/
void D_TurnZOn (void)
{
// not needed for software version
}
/*
===============
D_DisableBackBufferAccess
===============
*/
void D_DisableBackBufferAccess (void)
{
VID_UnlockBuffer ();
}
/*
===============
D_SetupFrame
===============
*/
void D_SetupFrame (void)
{
extern qboolean r_usinglits;
int i;
if (r_dowarp)
d_viewbuffer = r_warpbuffer;
else
d_viewbuffer = (void *)(qbyte *)vid.buffer;
if (r_dowarp)
screenwidth = WARP_WIDTH;
else
screenwidth = vid.rowbytes;
d_roverwrapped = false;
d_initial_rover = sc_rover;
d_minmip = d_mipcap.value;
if (d_minmip > 3)
d_minmip = 3;
else if (d_minmip < 0)
d_minmip = 0;
for (i=0 ; i<(NUM_MIPS-1) ; i++)
d_scalemip[i] = basemip[i] * d_mipscale.value;
#if id386
if (r_pixbytes == 4)
d_drawspans = d_smooth.value?D_DrawSpans32_Smooth:D_DrawSpans32;
else if (r_pixbytes == 2)
d_drawspans = D_DrawSpans16;
else if (d_smooth.value)//override's subdiv16 (bigger impact)
d_drawspans = D_DrawSpans8_Smooth;
else if (d_subdiv16.value)
d_drawspans = D_DrawSpans8SubDiv16;
else
d_drawspans = D_DrawSpans8;
#else
if (r_pixbytes == 4)
{
if (r_usinglits)
d_drawspans = d_smooth.value?D_DrawSpans32_Smooth:D_DrawSpans32;
else
d_drawspans = D_DrawSpans32From8;
}
else if (r_pixbytes == 2)
d_drawspans = D_DrawSpans16;
else
d_drawspans = d_smooth.value?D_DrawSpans8_Smooth:D_DrawSpans8;
#endif
d_aflatcolor = 0;
}
/*
===============
D_UpdateRects
===============
*/
void D_UpdateRects (vrect_t *prect)
{
// the software driver draws these directly to the vid buffer
UNUSED(prect);
}

136
engine/sw/d_local.h Normal file
View file

@ -0,0 +1,136 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_local.h: private rasterization driver defs
#include "r_shared.h"
//
// TODO: fine-tune this; it's based on providing some overage even if there
// is a 2k-wide scan, with subdivision every 8, for 256 spans of 12 bytes each
//
#define SCANBUFFERPAD 0x1000
#define R_SKY_SMASK 0x007F0000
#define R_SKY_TMASK 0x007F0000
#define DS_SPAN_LIST_END -128
#define SURFCACHE_SIZE_AT_320X200 600*1024
typedef struct surfcache_s
{
struct surfcache_s *next;
struct surfcache_s **owner; // NULL is an empty chunk of memory
int lightadj[MAXLIGHTMAPS]; // checked for strobe flush
int dlight;
int size; // including header
unsigned width;
unsigned height; // DEBUG only needed for debug
float mipscale;
struct texture_s *texture; // checked for animating textures
int bytesperpix;
int fcache;
qbyte data[4]; // width*height elements
} surfcache_t;
// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct sspan_s
{
int u, v, count;
} sspan_t;
extern cvar_t d_subdiv16;
extern float scale_for_mip;
extern qboolean d_roverwrapped;
extern surfcache_t *sc_rover;
extern surfcache_t *d_initial_rover;
extern float d_sdivzstepu, d_tdivzstepu, d_zistepu;
extern float d_sdivzstepv, d_tdivzstepv, d_zistepv;
extern float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
fixed16_t sadjust, tadjust;
fixed16_t bbextents, bbextentt;
void D_DrawSpans8_Smooth (espan_t *pspan);
void D_DrawSpans8 (espan_t *pspans);
void D_DrawSpans16 (espan_t *pspans);
void D_DrawSpans8SubDiv16 (espan_t *pspans);
void D_DrawSpans16From8 (espan_t *pspan); //skybox in 16 bit renderer (fixme - load tgas with more colourdepth).
void D_DrawZSpans (espan_t *pspans);
void Turbulent8 (espan_t *pspan);
void Turbulent16 (espan_t *pspan);
void Turbulent32 (espan_t *pspan);
void D_SpriteDrawSpans (sspan_t *pspan);
void D_DrawSkyScans8 (espan_t *pspan);
void D_DrawSkyScans16 (espan_t *pspan);
void D_DrawSkyScans32 (espan_t *pspan);
void R_ShowSubDiv (void);
void (*prealspandrawer)(void);
surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel);
extern int D_MipLevelForScale (float scale);
#if id386
extern void D_PolysetAff8Start (void);
extern void D_PolysetAff8End (void);
#endif
extern short *d_pzbuffer;
extern unsigned int d_zrowbytes, d_zwidth;
extern int *d_pscantable;
extern int d_scantable[MAXHEIGHT];
extern int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
extern int d_y_aspect_shift, d_pix_min, d_pix_max, d_pix_shift;
extern pixel_t *d_viewbuffer;
extern short *zspantable[MAXHEIGHT];
extern int d_minmip;
extern float d_scalemip[3];
extern void (*d_drawspans) (espan_t *pspan);
#ifdef PEXT_TRANS
typedef qbyte tlookup[256][256];
typedef qbyte tlookupp[256];
extern tlookup *t_lookup;
extern tlookupp *t_curlookupp;
extern int t_curtable;
extern int t_numtables;
extern int t_numtablesinv;//65546/numtables
void D_InitTrans(void);
#define Trans(p, p2) (t_curlookupp[p][p2])
void Set_TransLevelI(int level);
void Set_TransLevelF(float level);
#endif

115
engine/sw/d_modech.c Normal file
View file

@ -0,0 +1,115 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_modech.c: called when mode has just changed
//the id made assembler cannot cope with the changes made to the triangle data type.
#ifndef NOASM
#define NOASM
#endif
#include "quakedef.h"
#include "d_local.h"
int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
int d_y_aspect_shift, d_pix_min, d_pix_max, d_pix_shift;
int d_scantable[MAXHEIGHT];
short *zspantable[MAXHEIGHT];
/*
================
D_Patch
================
*/
void D_Patch (void)
{
#if id386
static qboolean protectset8 = false;
if (!protectset8)
{
Sys_MakeCodeWriteable ((int)D_PolysetAff8Start,
(int)D_PolysetAff8End - (int)D_PolysetAff8Start);
protectset8 = true;
}
#endif // id386
}
/*
================
D_ViewChanged
================
*/
void D_ViewChanged (void)
{
int rowbytes;
if (r_dowarp)
rowbytes = WARP_WIDTH;
else
rowbytes = vid.rowbytes;
scale_for_mip = xscale;
if (yscale > xscale)
scale_for_mip = yscale;
d_zrowbytes = vid.width * 2;
d_zwidth = vid.width;
d_pix_min = r_refdef.vrect.width / 320;
if (d_pix_min < 1)
d_pix_min = 1;
d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
d_pix_max*=2;
d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
if (d_pix_max < 1)
d_pix_max = 1;
if (pixelAspect > 1.4)
d_y_aspect_shift = 1;
else
d_y_aspect_shift = 0;
d_vrectx = r_refdef.vrect.x;
d_vrecty = r_refdef.vrect.y;
d_vrectright_particle = r_refdef.vrectright - d_pix_max;
d_vrectbottom_particle =
r_refdef.vrectbottom - (d_pix_max << d_y_aspect_shift);
{
int i;
for (i=0 ; i<vid.height; i++)
{
d_scantable[i] = i*rowbytes;
zspantable[i] = d_pzbuffer + i*d_zwidth;
}
}
D_Patch ();
D_FlushCaches();
}

868
engine/sw/d_part.c Normal file
View file

@ -0,0 +1,868 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_part.c: software driver module for drawing particles
#include "quakedef.h"
#include "d_local.h"
//Spike: Particles are depth sorted. So why depth write? They are the last to be drawn anyway.
/*
==============
D_EndParticles
==============
*/
void D_EndParticles (void)
{
// not used by software driver
}
/*
==============
D_StartParticles
==============
*/
void D_StartParticles (void)
{
// not used by software driver
}
#if !id386
/*
==============
D_DrawParticle
==============
*/
void D_DrawParticle (particle_t *pparticle)
{
vec3_t local, transformed;
float zi;
qbyte *pdest;
short *pz;
int i, izi, pix, count, u, v;
// transform point
VectorSubtract (pparticle->org, r_origin, local);
transformed[0] = DotProduct(local, r_pright);
transformed[1] = DotProduct(local, r_pup);
transformed[2] = DotProduct(local, r_ppn);
if (transformed[2] < PARTICLE_Z_CLIP)
return;
// project the point
// FIXME: preadjust xcenter and ycenter
zi = 1.0 / transformed[2];
u = (int)(xcenter + zi * transformed[0] + 0.5);
v = (int)(ycenter - zi * transformed[1] + 0.5);
if ((v > d_vrectbottom_particle) ||
(u > d_vrectright_particle) ||
(v < d_vrecty) ||
(u < d_vrectx))
{
return;
}
pz = d_pzbuffer + (d_zwidth * v) + u;
pdest = d_viewbuffer + d_scantable[v] + u;
izi = (int)(zi * 0x8000);
pix = izi >> d_pix_shift;
pix *= pparticle->scale;
if (pix < d_pix_min)
pix = d_pix_min;
else if (pix > d_pix_max)
pix = d_pix_max;
switch (pix)
{
case 1:
count = 1 << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
if (pz[0] <= izi)
{
// pz[0] = izi;
pdest[0] = pparticle->color;
}
}
break;
case 2:
count = 2 << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
if (pz[0] <= izi)
{
// pz[0] = izi;
pdest[0] = pparticle->color;
}
if (pz[1] <= izi)
{
// pz[1] = izi;
pdest[1] = pparticle->color;
}
}
break;
case 3:
count = 3 << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
if (pz[0] <= izi)
{
// pz[0] = izi;
pdest[0] = pparticle->color;
}
if (pz[1] <= izi)
{
// pz[1] = izi;
pdest[1] = pparticle->color;
}
if (pz[2] <= izi)
{
// pz[2] = izi;
pdest[2] = pparticle->color;
}
}
break;
case 4:
count = 4 << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
if (pz[0] <= izi)
{
// pz[0] = izi;
pdest[0] = pparticle->color;
}
if (pz[1] <= izi)
{
// pz[1] = izi;
pdest[1] = pparticle->color;
}
if (pz[2] <= izi)
{
// pz[2] = izi;
pdest[2] = pparticle->color;
}
if (pz[3] <= izi)
{
// pz[3] = izi;
pdest[3] = pparticle->color;
}
}
break;
default:
count = pix << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
for (i=0 ; i<pix ; i++)
{
if (pz[i] <= izi)
{
// pz[i] = izi;
pdest[i] = pparticle->color;
}
}
}
break;
}
}
#endif // !id386
void D_DrawParticle16 (particle_t *pparticle)
{
vec3_t local, transformed;
float zi;
unsigned short *pdest;
int a;
short *pz;
int i, izi, pix, count, u, v;
if (pparticle->alpha <= 0.2)
return;
// transform point
VectorSubtract (pparticle->org, r_origin, local);
transformed[0] = DotProduct(local, r_pright);
transformed[1] = DotProduct(local, r_pup);
transformed[2] = DotProduct(local, r_ppn);
if (transformed[2] < PARTICLE_Z_CLIP)
return;
// project the point
// FIXME: preadjust xcenter and ycenter
zi = 1.0 / transformed[2];
u = (int)(xcenter + zi * transformed[0] + 0.5);
v = (int)(ycenter - zi * transformed[1] + 0.5);
if ((v > d_vrectbottom_particle) ||
(u > d_vrectright_particle) ||
(v < d_vrecty) ||
(u < d_vrectx))
{
return;
}
pz = d_pzbuffer + (d_zwidth * v) + u;
izi = (int)(zi * 0x8000);
pix = ((int)(izi*pparticle->scale)) >> d_pix_shift;
if (pix < d_pix_min)
pix = d_pix_min;
else if (pix > d_pix_max)
pix = d_pix_max;
u -= pix/2;
v -= pix/2;
if (u < 0) u = 0;
if (v < 0) v = 0;
pdest = (unsigned short *)d_viewbuffer + ((d_scantable[v] + u));
a = 255*pparticle->alpha;
switch (pix)
{
default:
count = pix << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
for (i=0 ; i<pix ; i++)
{
if (pz[i] <= izi)
{
// pz[i] = izi;
pdest[i] = d_8to16table[(int)pparticle->color];
}
}
}
break;
}
}
void D_DrawParticle32 (particle_t *pparticle)
{
vec3_t local, transformed;
float zi;
qbyte *pdest;
qbyte *pal;
int a;
short *pz;
int i, izi, pix, count, u, v;
if (pparticle->alpha <= 0.0)
return;
// transform point
VectorSubtract (pparticle->org, r_origin, local);
transformed[0] = DotProduct(local, r_pright);
transformed[1] = DotProduct(local, r_pup);
transformed[2] = DotProduct(local, r_ppn);
if (transformed[2] < PARTICLE_Z_CLIP)
return;
// project the point
// FIXME: preadjust xcenter and ycenter
zi = 1.0 / transformed[2];
u = (int)(xcenter + zi * transformed[0] + 0.5);
v = (int)(ycenter - zi * transformed[1] + 0.5);
if ((v > d_vrectbottom_particle) ||
(u > d_vrectright_particle) ||
(v < d_vrecty) ||
(u < d_vrectx))
{
return;
}
pz = d_pzbuffer + (d_zwidth * v) + u;
izi = (int)(zi * 0x8000);
pix = ((int)(izi*pparticle->scale)) >> d_pix_shift;
if (pix < d_pix_min)
pix = d_pix_min;
else if (pix > d_pix_max)
pix = d_pix_max;
u -= pix/2;
v -= pix/2;
if (u < 0) u = 0;
if (v < 0) v = 0;
pdest = d_viewbuffer + ((d_scantable[v] + u)<<2);
pal = (qbyte *)&d_8to32table[(int)pparticle->color];
a = 255*pparticle->alpha;
switch (pix)
{
default:
count = pix << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth<<2)
{
for (i=0 ; i<pix ; i++)
{
if (pz[i] <= izi)
{
// pz[i] = izi;
pdest[(i<<2)+0] = (pdest[(i<<2)+0]*(255-a) + pal[0]*a) / 255;
pdest[(i<<2)+1] = (pdest[(i<<2)+1]*(255-a) + pal[1]*a) / 255;
pdest[(i<<2)+2] = (pdest[(i<<2)+2]*(255-a) + pal[2]*a) / 255;
}
}
}
break;
}
}
#define draw(x, y) x=Trans(x,(int)y)
void D_DrawParticleTrans (particle_t *pparticle)
{
vec3_t local, transformed;
float zi;
qbyte *pdest;
short *pz;
int i, izi, pix, count, u, v;
if (r_pixbytes == 4)
{
D_DrawParticle32(pparticle);
return;
}
if (r_pixbytes == 2)
{
D_DrawParticle16(pparticle);
return;
}
if (pparticle->alpha <= 0.0)
return;
if (pparticle->alpha >= 0.9)
{
D_DrawParticle(pparticle);
return;
}
Set_TransLevelF(pparticle->alpha);
// transform point
VectorSubtract (pparticle->org, r_origin, local);
transformed[0] = DotProduct(local, r_pright);
transformed[1] = DotProduct(local, r_pup);
transformed[2] = DotProduct(local, r_ppn);
if (transformed[2] < PARTICLE_Z_CLIP)
return;
// project the point
// FIXME: preadjust xcenter and ycenter
zi = 1.0 / transformed[2];
u = (int)(xcenter + zi * transformed[0] + 0.5);
v = (int)(ycenter - zi * transformed[1] + 0.5);
if ((v > d_vrectbottom_particle) ||
(u > d_vrectright_particle) ||
(v < d_vrecty) ||
(u < d_vrectx))
{
return;
}
pz = d_pzbuffer + (d_zwidth * v) + u;
izi = (int)(zi * 0x8000);
pix = ((int)(izi*pparticle->scale)) >> d_pix_shift;
if (pix < d_pix_min)
pix = d_pix_min;
else if (pix > d_pix_max)
pix = d_pix_max;
u -= pix/2;
v -= pix/2;
if (u < 0) u = 0;
if (v < 0) v = 0;
pdest = d_viewbuffer + d_scantable[v] + u;
switch (pix)
{
case 1:
count = 1 << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
if (pz[0] <= izi)
{
// pz[0] = izi;
draw(pdest[0], pparticle->color);
}
}
break;
case 2:
count = 2 << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
if (pz[0] <= izi)
{
// pz[0] = izi;
draw(pdest[0], pparticle->color);
}
if (pz[1] <= izi)
{
// pz[1] = izi;
draw(pdest[1], pparticle->color);
}
}
break;
case 3:
count = 3 << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
if (pz[0] <= izi)
{
// pz[0] = izi;
draw(pdest[0], pparticle->color);
}
if (pz[1] <= izi)
{
// pz[1] = izi;
draw(pdest[1], pparticle->color);
}
if (pz[2] <= izi)
{
// pz[2] = izi;
draw(pdest[2], pparticle->color);
}
}
break;
case 4:
count = 4 << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
if (pz[0] <= izi)
{
// pz[0] = izi;
draw(pdest[0], pparticle->color);
}
if (pz[1] <= izi)
{
// pz[1] = izi;
draw(pdest[1], pparticle->color);
}
if (pz[2] <= izi)
{
// pz[2] = izi;
draw(pdest[2], pparticle->color);
}
if (pz[3] <= izi)
{
// pz[3] = izi;
draw(pdest[3], pparticle->color);
}
}
break;
default:
count = pix << d_y_aspect_shift;
for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
{
for (i=0 ; i<pix ; i++)
{
if (pz[i] <= izi)
{
// pz[i] = izi;
draw(pdest[i], pparticle->color);
}
}
}
break;
}
}
void D_2dPos(vec3_t pos, int *u, int *v, int *z)
{
float zi;
vec3_t local, transformed;
// transform point
VectorSubtract (pos, r_origin, local);
transformed[2] = DotProduct(local, r_ppn);
if (transformed[2] < PARTICLE_Z_CLIP) //near clip
{
*u = -1; //send it off the side intentionally.
return;
}
transformed[0] = DotProduct(local, r_pright);
transformed[1] = DotProduct(local, r_pup);
// project the point
zi = 1.0 / transformed[2];
*u = (int)(xcenter + zi * transformed[0] + 0.5);
*v = (int)(ycenter - zi * transformed[1] + 0.5);
*z = (int)(zi * 0x8000);
}
vec_t VI2Length(int x, int y)
{
float length;
length = (float)x*x + (float)y*y;
length = sqrt (length);
return length;
}
void D_DrawSparkTrans32 (particle_t *pparticle) //draw a line in 3d space
{
/*
Finds 2d coords for the points, then draws a line between them with an appropriate alpha
*/
vec3_t delta;
unsigned char *pdest;
unsigned char *pal;
short *pz;
int count, u1, v1, z1, a1, a, ia;
int u2, v2, z2;
float speed;
int du, dv, dz, da;
if (pparticle->alpha <= 0.0)
return;
speed = Length(pparticle->vel);
if ((speed) < 1)
{
D_2dPos(pparticle->org, &u1, &v1, &z1);
D_2dPos(pparticle->org, &u2, &v2, &z2);
}
else
{ //causes flickers with lower vels (due to bouncing in physics)
if (speed < 50)
speed *= 50/speed;
VectorMA(pparticle->org, 5/(speed), pparticle->vel, delta);
D_2dPos(delta, &u1, &v1, &z1);
VectorMA(pparticle->org, -5/(speed), pparticle->vel, delta);
D_2dPos(delta, &u2, &v2, &z2);
}
if ((v1 > d_vrectbottom_particle) ||
(u1 > d_vrectright_particle) ||
(v1 < d_vrecty) ||
(u1 < d_vrectx))
{
return;
}
if ((v2 > d_vrectbottom_particle) ||
(u2 > d_vrectright_particle) ||
(v2 < d_vrecty) ||
(u2 < d_vrectx))
{
return;
}
pal = (qbyte *)(d_8to32table + (int)pparticle->color);
a1 = 255 * pparticle->alpha;
du = u2 - u1;
dv = v2 - v1;
dz = z2 - z1;
da = 0 - a1;
if (!du && !dv)
count = 1;
else
{
count = VI2Length(du, dv);
if (!count)
count = 1;
}
du *= 256*256;
dv *= 256*256;
dz *= 256*256;
da *= 256*256;
u1 = u1<<16;
v1 = v1<<16;
z1 = z1<<16;
a1 = a1<<16;
{
du /= count;
dv /= count;
dz /= count;
da /= count;
}
do
{
pz = d_pzbuffer + (d_zwidth * (v1>>16)) + (u1>>16);
if (*pz <= z1>>16)
{
// *pz = z1>>16;
a = a1>>16;
ia = 255-a;
pdest = (qbyte *)((unsigned int *)d_viewbuffer + ((d_scantable[v1>>16] + (u1>>16))));
pdest[0] = (pdest[0]*((ia)) + pal[0]*(a))/255;
pdest[1] = (pdest[1]*((ia)) + pal[1]*(a))/255;
pdest[2] = (pdest[2]*((ia)) + pal[2]*(a))/255;
}
u1 += du;
v1 += dv;
z1 += dz;
a1 += da;
} while (count--);
}
void D_DrawSparkTrans16 (particle_t *pparticle) //draw a line in 3d space, 8bpp
{
vec3_t delta;
unsigned short *pdest;
short *pz;
int count, u1, v1, z1;
int u2, v2, z2;
float speed;
int du, dv, dz;
if (pparticle->alpha <= 0.0)
return;
speed = Length(pparticle->vel);
if ((speed) < 1)
{
D_2dPos(pparticle->org, &u1, &v1, &z1);
D_2dPos(pparticle->org, &u2, &v2, &z2);
}
else
{ //causes flickers with lower vels (due to bouncing in physics)
if (speed < 50)
speed *= 50/speed;
VectorMA(pparticle->org, 2.5/(speed), pparticle->vel, delta);
D_2dPos(delta, &u1, &v1, &z1);
VectorMA(pparticle->org, -2.5/(speed), pparticle->vel, delta);
D_2dPos(delta, &u2, &v2, &z2);
}
if ((v1 > d_vrectbottom_particle) ||
(u1 > d_vrectright_particle) ||
(v1 < d_vrecty) ||
(u1 < d_vrectx))
{
return;
}
if ((v2 > d_vrectbottom_particle) ||
(u2 > d_vrectright_particle) ||
(v2 < d_vrecty) ||
(u2 < d_vrectx))
{
return;
}
du = u2 - u1;
dv = v2 - v1;
dz = z2 - z1;
if (!du && !dv)
count = 1;
else
{
count = VI2Length(du, dv);
if (!count)
count = 1;
}
du *= 256*256;
dv *= 256*256;
dz *= 256*256;
u1 = u1<<16;
v1 = v1<<16;
z1 = z1<<16;
{
du /= count;
dv /= count;
dz /= count;
}
do
{
pz = d_pzbuffer + (d_zwidth * (v1>>16)) + (u1>>16);
if (*pz <= z1>>16)
{
// *pz = z1>>16;
pdest = (unsigned short*)d_viewbuffer + d_scantable[v1>>16] + (u1>>16);
*pdest = d_8to16table[(int)pparticle->color];
}
u1 += du;
v1 += dv;
z1 += dz;
} while (count--);
}
void D_DrawSparkTrans (particle_t *pparticle) //draw a line in 3d space, 8bpp
{
vec3_t delta;
qbyte *pdest;
short *pz;
int count, u1, v1, z1;
int u2, v2, z2;
float speed;
int du, dv, dz;
/*
D_DrawParticleTrans(pparticle);
return;
*/
if (r_pixbytes == 4)
{
D_DrawSparkTrans32(pparticle);
return;
}
if (r_pixbytes == 2)
{
D_DrawSparkTrans16(pparticle);
return;
}
if (pparticle->alpha <= 0.0)
return;
Set_TransLevelF(pparticle->alpha);
speed = Length(pparticle->vel);
if ((speed) < 1)
{
D_2dPos(pparticle->org, &u1, &v1, &z1);
D_2dPos(pparticle->org, &u2, &v2, &z2);
}
else
{ //causes flickers with lower vels (due to bouncing in physics)
if (speed < 50)
speed *= 50/speed;
VectorMA(pparticle->org, 2.5/(speed), pparticle->vel, delta);
D_2dPos(delta, &u1, &v1, &z1);
VectorMA(pparticle->org, -2.5/(speed), pparticle->vel, delta);
D_2dPos(delta, &u2, &v2, &z2);
}
if ((v1 > d_vrectbottom_particle) ||
(u1 > d_vrectright_particle) ||
(v1 < d_vrecty) ||
(u1 < d_vrectx))
{
return;
}
if ((v2 > d_vrectbottom_particle) ||
(u2 > d_vrectright_particle) ||
(v2 < d_vrecty) ||
(u2 < d_vrectx))
{
return;
}
du = u2 - u1;
dv = v2 - v1;
dz = z2 - z1;
if (!du && !dv)
count = 1;
else
{
count = VI2Length(du, dv);
if (!count)
count = 1;
}
du *= 256*256;
dv *= 256*256;
dz *= 256*256;
u1 = u1<<16;
v1 = v1<<16;
z1 = z1<<16;
{
du /= count;
dv /= count;
dz /= count;
}
do
{
pz = d_pzbuffer + (d_zwidth * (v1>>16)) + (u1>>16);
if (*pz <= z1>>16)
{
// *pz = z1>>16;
pdest = d_viewbuffer + d_scantable[v1>>16] + (u1>>16);
draw(*pdest, pparticle->color);
}
u1 += du;
v1 += dv;
z1 += dz;
} while (count--);
}

477
engine/sw/d_parta.s Normal file
View file

@ -0,0 +1,477 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// d_parta.s
// x86 assembly-language 8-bpp particle-drawing code.
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "d_ifacea.h"
#include "asm_draw.h"
#if id386
//----------------------------------------------------------------------
// 8-bpp particle drawing code.
//----------------------------------------------------------------------
//FIXME: comments, full optimization
//----------------------------------------------------------------------
// 8-bpp particle queueing code.
//----------------------------------------------------------------------
.text
#define P 12+4
.align 4
.globl C(D_DrawParticle)
C(D_DrawParticle):
pushl %ebp // preserve caller's stack frame
pushl %edi // preserve register variables
pushl %ebx
movl P(%esp),%edi
// FIXME: better FP overlap in general here
// transform point
// VectorSubtract (p->org, r_origin, local);
flds C(r_origin)
fsubrs pt_org(%edi)
flds pt_org+4(%edi)
fsubs C(r_origin)+4
flds pt_org+8(%edi)
fsubs C(r_origin)+8
fxch %st(2) // local[0] | local[1] | local[2]
// transformed[2] = DotProduct(local, r_ppn);
flds C(r_ppn) // r_ppn[0] | local[0] | local[1] | local[2]
fmul %st(1),%st(0) // dot0 | local[0] | local[1] | local[2]
flds C(r_ppn)+4 // r_ppn[1] | dot0 | local[0] | local[1] | local[2]
fmul %st(3),%st(0) // dot1 | dot0 | local[0] | local[1] | local[2]
flds C(r_ppn)+8 // r_ppn[2] | dot1 | dot0 | local[0] |
// local[1] | local[2]
fmul %st(5),%st(0) // dot2 | dot1 | dot0 | local[0] | local[1] | local[2]
fxch %st(2) // dot0 | dot1 | dot2 | local[0] | local[1] | local[2]
faddp %st(0),%st(1) // dot0 + dot1 | dot2 | local[0] | local[1] |
// local[2]
faddp %st(0),%st(1) // z | local[0] | local[1] | local[2]
fld %st(0) // z | z | local[0] | local[1] |
// local[2]
fdivrs float_1 // 1/z | z | local[0] | local[1] | local[2]
fxch %st(1) // z | 1/z | local[0] | local[1] | local[2]
// if (transformed[2] < PARTICLE_Z_CLIP)
// return;
fcomps float_particle_z_clip // 1/z | local[0] | local[1] | local[2]
fxch %st(3) // local[2] | local[0] | local[1] | 1/z
flds C(r_pup) // r_pup[0] | local[2] | local[0] | local[1] | 1/z
fmul %st(2),%st(0) // dot0 | local[2] | local[0] | local[1] | 1/z
flds C(r_pup)+4 // r_pup[1] | dot0 | local[2] | local[0] |
// local[1] | 1/z
fnstsw %ax
testb $1,%ah
jnz LPop6AndDone
// transformed[1] = DotProduct(local, r_pup);
fmul %st(4),%st(0) // dot1 | dot0 | local[2] | local[0] | local[1] | 1/z
flds C(r_pup)+8 // r_pup[2] | dot1 | dot0 | local[2] |
// local[0] | local[1] | 1/z
fmul %st(3),%st(0) // dot2 | dot1 | dot0 | local[2] | local[0] |
// local[1] | 1/z
fxch %st(2) // dot0 | dot1 | dot2 | local[2] | local[0] |
// local[1] | 1/z
faddp %st(0),%st(1) // dot0 + dot1 | dot2 | local[2] | local[0] |
// local[1] | 1/z
faddp %st(0),%st(1) // y | local[2] | local[0] | local[1] | 1/z
fxch %st(3) // local[1] | local[2] | local[0] | y | 1/z
// transformed[0] = DotProduct(local, r_pright);
fmuls C(r_pright)+4 // dot1 | local[2] | local[0] | y | 1/z
fxch %st(2) // local[0] | local[2] | dot1 | y | 1/z
fmuls C(r_pright) // dot0 | local[2] | dot1 | y | 1/z
fxch %st(1) // local[2] | dot0 | dot1 | y | 1/z
fmuls C(r_pright)+8 // dot2 | dot0 | dot1 | y | 1/z
fxch %st(2) // dot1 | dot0 | dot2 | y | 1/z
faddp %st(0),%st(1) // dot1 + dot0 | dot2 | y | 1/z
faddp %st(0),%st(1) // x | y | 1/z
fxch %st(1) // y | x | 1/z
// project the point
fmul %st(2),%st(0) // y/z | x | 1/z
fxch %st(1) // x | y/z | 1/z
fmul %st(2),%st(0) // x/z | y/z | 1/z
fxch %st(1) // y/z | x/z | 1/z
fsubrs C(ycenter) // v | x/z | 1/z
fxch %st(1) // x/z | v | 1/z
fadds C(xcenter) // u | v | 1/z
// FIXME: preadjust xcenter and ycenter
fxch %st(1) // v | u | 1/z
fadds float_point5 // v | u | 1/z
fxch %st(1) // u | v | 1/z
fadds float_point5 // u | v | 1/z
fxch %st(2) // 1/z | v | u
fmuls DP_32768 // 1/z * 0x8000 | v | u
fxch %st(2) // u | v | 1/z * 0x8000
// FIXME: use Terje's fp->int trick here?
// FIXME: check we're getting proper rounding here
fistpl DP_u // v | 1/z * 0x8000
fistpl DP_v // 1/z * 0x8000
movl DP_u,%eax
movl DP_v,%edx
// if ((v > d_vrectbottom_particle) ||
// (u > d_vrectright_particle) ||
// (v < d_vrecty) ||
// (u < d_vrectx))
// {
// continue;
// }
movl C(d_vrectbottom_particle),%ebx
movl C(d_vrectright_particle),%ecx
cmpl %ebx,%edx
jg LPop1AndDone
cmpl %ecx,%eax
jg LPop1AndDone
movl C(d_vrecty),%ebx
movl C(d_vrectx),%ecx
cmpl %ebx,%edx
jl LPop1AndDone
cmpl %ecx,%eax
jl LPop1AndDone
flds pt_color(%edi) // color | 1/z * 0x8000
// FIXME: use Terje's fast fp->int trick?
fistpl DP_Color // 1/z * 0x8000
movl C(d_viewbuffer),%ebx
addl %eax,%ebx
movl C(d_scantable)(,%edx,4),%edi // point to the pixel
imull C(d_zrowbytes),%edx // point to the z pixel
leal (%edx,%eax,2),%edx
movl C(d_pzbuffer),%eax
fistpl izi
addl %ebx,%edi
addl %eax,%edx
// pix = izi >> d_pix_shift;
movl izi,%eax
movl C(d_pix_shift),%ecx
shrl %cl,%eax
movl izi,%ebp
// if (pix < d_pix_min)
// pix = d_pix_min;
// else if (pix > d_pix_max)
// pix = d_pix_max;
movl C(d_pix_min),%ebx
movl C(d_pix_max),%ecx
cmpl %ebx,%eax
jnl LTestPixMax
movl %ebx,%eax
jmp LTestDone
LTestPixMax:
cmpl %ecx,%eax
jng LTestDone
movl %ecx,%eax
LTestDone:
movb DP_Color,%ch
movl C(d_y_aspect_shift),%ebx
testl %ebx,%ebx
jnz LDefault
cmpl $4,%eax
ja LDefault
jmp DP_EntryTable-4(,%eax,4)
// 1x1
.globl DP_1x1
DP_1x1:
cmpw %bp,(%edx) // just one pixel to do
jg LDone
movw %bp,(%edx)
movb %ch,(%edi)
jmp LDone
// 2x2
.globl DP_2x2
DP_2x2:
pushl %esi
movl C(screenwidth),%ebx
movl C(d_zrowbytes),%esi
cmpw %bp,(%edx)
jg L2x2_1
movw %bp,(%edx)
movb %ch,(%edi)
L2x2_1:
cmpw %bp,2(%edx)
jg L2x2_2
movw %bp,2(%edx)
movb %ch,1(%edi)
L2x2_2:
cmpw %bp,(%edx,%esi,1)
jg L2x2_3
movw %bp,(%edx,%esi,1)
movb %ch,(%edi,%ebx,1)
L2x2_3:
cmpw %bp,2(%edx,%esi,1)
jg L2x2_4
movw %bp,2(%edx,%esi,1)
movb %ch,1(%edi,%ebx,1)
L2x2_4:
popl %esi
jmp LDone
// 3x3
.globl DP_3x3
DP_3x3:
pushl %esi
movl C(screenwidth),%ebx
movl C(d_zrowbytes),%esi
cmpw %bp,(%edx)
jg L3x3_1
movw %bp,(%edx)
movb %ch,(%edi)
L3x3_1:
cmpw %bp,2(%edx)
jg L3x3_2
movw %bp,2(%edx)
movb %ch,1(%edi)
L3x3_2:
cmpw %bp,4(%edx)
jg L3x3_3
movw %bp,4(%edx)
movb %ch,2(%edi)
L3x3_3:
cmpw %bp,(%edx,%esi,1)
jg L3x3_4
movw %bp,(%edx,%esi,1)
movb %ch,(%edi,%ebx,1)
L3x3_4:
cmpw %bp,2(%edx,%esi,1)
jg L3x3_5
movw %bp,2(%edx,%esi,1)
movb %ch,1(%edi,%ebx,1)
L3x3_5:
cmpw %bp,4(%edx,%esi,1)
jg L3x3_6
movw %bp,4(%edx,%esi,1)
movb %ch,2(%edi,%ebx,1)
L3x3_6:
cmpw %bp,(%edx,%esi,2)
jg L3x3_7
movw %bp,(%edx,%esi,2)
movb %ch,(%edi,%ebx,2)
L3x3_7:
cmpw %bp,2(%edx,%esi,2)
jg L3x3_8
movw %bp,2(%edx,%esi,2)
movb %ch,1(%edi,%ebx,2)
L3x3_8:
cmpw %bp,4(%edx,%esi,2)
jg L3x3_9
movw %bp,4(%edx,%esi,2)
movb %ch,2(%edi,%ebx,2)
L3x3_9:
popl %esi
jmp LDone
// 4x4
.globl DP_4x4
DP_4x4:
pushl %esi
movl C(screenwidth),%ebx
movl C(d_zrowbytes),%esi
cmpw %bp,(%edx)
jg L4x4_1
movw %bp,(%edx)
movb %ch,(%edi)
L4x4_1:
cmpw %bp,2(%edx)
jg L4x4_2
movw %bp,2(%edx)
movb %ch,1(%edi)
L4x4_2:
cmpw %bp,4(%edx)
jg L4x4_3
movw %bp,4(%edx)
movb %ch,2(%edi)
L4x4_3:
cmpw %bp,6(%edx)
jg L4x4_4
movw %bp,6(%edx)
movb %ch,3(%edi)
L4x4_4:
cmpw %bp,(%edx,%esi,1)
jg L4x4_5
movw %bp,(%edx,%esi,1)
movb %ch,(%edi,%ebx,1)
L4x4_5:
cmpw %bp,2(%edx,%esi,1)
jg L4x4_6
movw %bp,2(%edx,%esi,1)
movb %ch,1(%edi,%ebx,1)
L4x4_6:
cmpw %bp,4(%edx,%esi,1)
jg L4x4_7
movw %bp,4(%edx,%esi,1)
movb %ch,2(%edi,%ebx,1)
L4x4_7:
cmpw %bp,6(%edx,%esi,1)
jg L4x4_8
movw %bp,6(%edx,%esi,1)
movb %ch,3(%edi,%ebx,1)
L4x4_8:
leal (%edx,%esi,2),%edx
leal (%edi,%ebx,2),%edi
cmpw %bp,(%edx)
jg L4x4_9
movw %bp,(%edx)
movb %ch,(%edi)
L4x4_9:
cmpw %bp,2(%edx)
jg L4x4_10
movw %bp,2(%edx)
movb %ch,1(%edi)
L4x4_10:
cmpw %bp,4(%edx)
jg L4x4_11
movw %bp,4(%edx)
movb %ch,2(%edi)
L4x4_11:
cmpw %bp,6(%edx)
jg L4x4_12
movw %bp,6(%edx)
movb %ch,3(%edi)
L4x4_12:
cmpw %bp,(%edx,%esi,1)
jg L4x4_13
movw %bp,(%edx,%esi,1)
movb %ch,(%edi,%ebx,1)
L4x4_13:
cmpw %bp,2(%edx,%esi,1)
jg L4x4_14
movw %bp,2(%edx,%esi,1)
movb %ch,1(%edi,%ebx,1)
L4x4_14:
cmpw %bp,4(%edx,%esi,1)
jg L4x4_15
movw %bp,4(%edx,%esi,1)
movb %ch,2(%edi,%ebx,1)
L4x4_15:
cmpw %bp,6(%edx,%esi,1)
jg L4x4_16
movw %bp,6(%edx,%esi,1)
movb %ch,3(%edi,%ebx,1)
L4x4_16:
popl %esi
jmp LDone
// default case, handling any size particle
LDefault:
// count = pix << d_y_aspect_shift;
movl %eax,%ebx
movl %eax,DP_Pix
movb C(d_y_aspect_shift),%cl
shll %cl,%ebx
// for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
// {
// for (i=0 ; i<pix ; i++)
// {
// if (pz[i] <= izi)
// {
// pz[i] = izi;
// pdest[i] = color;
// }
// }
// }
LGenRowLoop:
movl DP_Pix,%eax
LGenColLoop:
cmpw %bp,-2(%edx,%eax,2)
jg LGSkip
movw %bp,-2(%edx,%eax,2)
movb %ch,-1(%edi,%eax,1)
LGSkip:
decl %eax // --pix
jnz LGenColLoop
addl C(d_zrowbytes),%edx
addl C(screenwidth),%edi
decl %ebx // --count
jnz LGenRowLoop
LDone:
popl %ebx // restore register variables
popl %edi
popl %ebp // restore the caller's stack frame
ret
LPop6AndDone:
fstp %st(0)
fstp %st(0)
fstp %st(0)
fstp %st(0)
fstp %st(0)
LPop1AndDone:
fstp %st(0)
jmp LDone
#endif // id386

1759
engine/sw/d_polysa.s Normal file

File diff suppressed because it is too large Load diff

2446
engine/sw/d_polyse.c Normal file

File diff suppressed because it is too large Load diff

1728
engine/sw/d_scan.c Normal file

File diff suppressed because it is too large Load diff

89
engine/sw/d_scana.s Normal file
View file

@ -0,0 +1,89 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// d_scana.s
// x86 assembly-language turbulent texture mapping code
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"
#if id386
.data
.text
//----------------------------------------------------------------------
// turbulent texture mapping code
//----------------------------------------------------------------------
.align 4
.globl C(D_DrawTurbulent8Span)
C(D_DrawTurbulent8Span):
pushl %ebp // preserve caller's stack frame pointer
pushl %esi // preserve register variables
pushl %edi
pushl %ebx
movl C(r_turb_s),%esi
movl C(r_turb_t),%ecx
movl C(r_turb_pdest),%edi
movl C(r_turb_spancount),%ebx
Llp:
movl %ecx,%eax
movl %esi,%edx
sarl $16,%eax
movl C(r_turb_turb),%ebp
sarl $16,%edx
andl $(CYCLE-1),%eax
andl $(CYCLE-1),%edx
movl (%ebp,%eax,4),%eax
movl (%ebp,%edx,4),%edx
addl %esi,%eax
sarl $16,%eax
addl %ecx,%edx
sarl $16,%edx
andl $(TURB_TEX_SIZE-1),%eax
andl $(TURB_TEX_SIZE-1),%edx
shll $6,%edx
movl C(r_turb_pbase),%ebp
addl %eax,%edx
incl %edi
addl C(r_turb_sstep),%esi
addl C(r_turb_tstep),%ecx
movb (%ebp,%edx,1),%dl
decl %ebx
movb %dl,-1(%edi)
jnz Llp
movl %edi,C(r_turb_pdest)
popl %ebx // restore register variables
popl %edi
popl %esi
popl %ebp // restore caller's stack frame pointer
ret
#endif // id386

301
engine/sw/d_sky.c Normal file
View file

@ -0,0 +1,301 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_sky.c
#include "quakedef.h"
#include "r_local.h"
#include "d_local.h"
#define SKY_SPAN_SHIFT 5
#define SKY_SPAN_MAX (1 << SKY_SPAN_SHIFT)
/*
=================
D_Sky_uv_To_st
=================
*/
void D_Sky_uv_To_st (int u, int v, fixed16_t *s, fixed16_t *t)
{
float wu, wv, temp;
vec3_t end;
if (r_refdef.vrect.width >= r_refdef.vrect.height)
temp = (float)r_refdef.vrect.width;
else
temp = (float)r_refdef.vrect.height;
wu = 8192.0 * (float)(u-((int)vid.width>>1)) / temp;
wv = 8192.0 * (float)(((int)vid.height>>1)-v) / temp;
end[0] = 4096*vpn[0] + wu*vright[0] + wv*vup[0];
end[1] = 4096*vpn[1] + wu*vright[1] + wv*vup[1];
end[2] = 4096*vpn[2] + wu*vright[2] + wv*vup[2];
end[2] *= 3;
VectorNormalize (end);
temp = skytime*skyspeed; // TODO: add D_SetupFrame & set this there
*s = (int)((temp + 6*(SKYSIZE/2-1)*end[0]) * 0x10000);
*t = (int)((temp + 6*(SKYSIZE/2-1)*end[1]) * 0x10000);
}
/*
=================
D_DrawSkyScans8
=================
*/
void D_DrawSkyScans8 (espan_t *pspan)
{
int count, spancount, u, v;
unsigned char *pdest;
fixed16_t s, t, snext, tnext, sstep, tstep;
int spancountminus1;
sstep = 0; // keep compiler happy
tstep = 0; // ditto
do
{
pdest = (unsigned char *)((qbyte *)d_viewbuffer +
(screenwidth * pspan->v) + pspan->u);
count = pspan->count;
// calculate the initial s & t
u = pspan->u;
v = pspan->v;
D_Sky_uv_To_st (u, v, &s, &t);
do
{
if (count >= SKY_SPAN_MAX)
spancount = SKY_SPAN_MAX;
else
spancount = count;
count -= spancount;
if (count)
{
u += spancount;
// calculate s and t at far end of span,
// calculate s and t steps across span by shifting
D_Sky_uv_To_st (u, v, &snext, &tnext);
sstep = (snext - s) >> SKY_SPAN_SHIFT;
tstep = (tnext - t) >> SKY_SPAN_SHIFT;
}
else
{
// calculate s and t at last pixel in span,
// calculate s and t steps across span by division
spancountminus1 = (float)(spancount - 1);
if (spancountminus1 > 0)
{
u += spancountminus1;
D_Sky_uv_To_st (u, v, &snext, &tnext);
sstep = (snext - s) / spancountminus1;
tstep = (tnext - t) / spancountminus1;
}
else
{
snext = 0;
tnext = 0;
}
}
do
{
*pdest++ = r_skysource[((t & R_SKY_TMASK) >> 8) +
((s & R_SKY_SMASK) >> 16)];
s += sstep;
t += tstep;
} while (--spancount > 0);
s = snext;
t = tnext;
} while (count > 0);
} while ((pspan = pspan->pnext) != NULL);
}
void D_DrawSkyScans16 (espan_t *pspan)
{
int count, spancount, u, v;
unsigned short *pdest;
fixed16_t s, t, snext, tnext, sstep, tstep;
int spancountminus1;
sstep = 0; // keep compiler happy
tstep = 0; // ditto
do
{
pdest = ((unsigned short *)d_viewbuffer +
(screenwidth * pspan->v) + pspan->u);
count = pspan->count;
// calculate the initial s & t
u = pspan->u;
v = pspan->v;
D_Sky_uv_To_st (u, v, &s, &t);
do
{
if (count >= SKY_SPAN_MAX)
spancount = SKY_SPAN_MAX;
else
spancount = count;
count -= spancount;
if (count)
{
u += spancount;
// calculate s and t at far end of span,
// calculate s and t steps across span by shifting
D_Sky_uv_To_st (u, v, &snext, &tnext);
sstep = (snext - s) >> SKY_SPAN_SHIFT;
tstep = (tnext - t) >> SKY_SPAN_SHIFT;
}
else
{
// calculate s and t at last pixel in span,
// calculate s and t steps across span by division
spancountminus1 = (float)(spancount - 1);
if (spancountminus1 > 0)
{
u += spancountminus1;
D_Sky_uv_To_st (u, v, &snext, &tnext);
sstep = (snext - s) / spancountminus1;
tstep = (tnext - t) / spancountminus1;
}
else
{
snext=0;
tnext=0;
}
}
do
{
*pdest++ = d_8to16table[r_skysource[((t & R_SKY_TMASK) >> 8) +
((s & R_SKY_SMASK) >> 16)]];
s += sstep;
t += tstep;
} while (--spancount > 0);
s = snext;
t = tnext;
} while (count > 0);
} while ((pspan = pspan->pnext) != NULL);
}
void D_DrawSkyScans32 (espan_t *pspan)
{
int count, spancount, u, v;
unsigned int *pdest;
fixed16_t s, t, snext, tnext, sstep, tstep;
int spancountminus1;
sstep = 0; // keep compiler happy
tstep = 0; // ditto
do
{
pdest = ((unsigned int *)d_viewbuffer +
(screenwidth * pspan->v) + pspan->u);
count = pspan->count;
// calculate the initial s & t
u = pspan->u;
v = pspan->v;
D_Sky_uv_To_st (u, v, &s, &t);
do
{
if (count >= SKY_SPAN_MAX)
spancount = SKY_SPAN_MAX;
else
spancount = count;
count -= spancount;
if (count)
{
u += spancount;
// calculate s and t at far end of span,
// calculate s and t steps across span by shifting
D_Sky_uv_To_st (u, v, &snext, &tnext);
sstep = (snext - s) >> SKY_SPAN_SHIFT;
tstep = (tnext - t) >> SKY_SPAN_SHIFT;
}
else
{
// calculate s and t at last pixel in span,
// calculate s and t steps across span by division
spancountminus1 = (float)(spancount - 1);
if (spancountminus1 > 0)
{
u += spancountminus1;
D_Sky_uv_To_st (u, v, &snext, &tnext);
sstep = (snext - s) / spancountminus1;
tstep = (tnext - t) / spancountminus1;
}
else
{
snext=0;
tnext=0;
}
}
do
{
*pdest++ = d_8to32table[r_skysource[((t & R_SKY_TMASK) >> 8) +
((s & R_SKY_SMASK) >> 16)]];
s += sstep;
t += tstep;
} while (--spancount > 0);
s = snext;
t = tnext;
} while (count > 0);
} while ((pspan = pspan->pnext) != NULL);
}

899
engine/sw/d_spr8.s Normal file
View file

@ -0,0 +1,899 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// d_spr8.s
// x86 assembly-language horizontal 8-bpp transparent span-drawing code.
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#if id386
//----------------------------------------------------------------------
// 8-bpp horizontal span drawing code for polygons, with transparency.
//----------------------------------------------------------------------
.text
// out-of-line, rarely-needed clamping code
LClampHigh0:
movl C(bbextents),%esi
jmp LClampReentry0
LClampHighOrLow0:
jg LClampHigh0
xorl %esi,%esi
jmp LClampReentry0
LClampHigh1:
movl C(bbextentt),%edx
jmp LClampReentry1
LClampHighOrLow1:
jg LClampHigh1
xorl %edx,%edx
jmp LClampReentry1
LClampLow2:
movl $2048,%ebp
jmp LClampReentry2
LClampHigh2:
movl C(bbextents),%ebp
jmp LClampReentry2
LClampLow3:
movl $2048,%ecx
jmp LClampReentry3
LClampHigh3:
movl C(bbextentt),%ecx
jmp LClampReentry3
LClampLow4:
movl $2048,%eax
jmp LClampReentry4
LClampHigh4:
movl C(bbextents),%eax
jmp LClampReentry4
LClampLow5:
movl $2048,%ebx
jmp LClampReentry5
LClampHigh5:
movl C(bbextentt),%ebx
jmp LClampReentry5
#define pspans 4+16
.align 4
.globl C(D_SpriteDrawSpans)
C(D_SpriteDrawSpans):
pushl %ebp // preserve caller's stack frame
pushl %edi
pushl %esi // preserve register variables
pushl %ebx
//
// set up scaled-by-8 steps, for 8-long segments; also set up cacheblock
// and span list pointers, and 1/z step in 0.32 fixed-point
//
// FIXME: any overlap from rearranging?
flds C(d_sdivzstepu)
fmuls fp_8
movl C(cacheblock),%edx
flds C(d_tdivzstepu)
fmuls fp_8
movl pspans(%esp),%ebx // point to the first span descriptor
flds C(d_zistepu)
fmuls fp_8
movl %edx,pbase // pbase = cacheblock
flds C(d_zistepu)
fmuls fp_64kx64k
fxch %st(3)
fstps sdivz8stepu
fstps zi8stepu
fstps tdivz8stepu
fistpl izistep
movl izistep,%eax
rorl $16,%eax // put upper 16 bits in low word
movl sspan_t_count(%ebx),%ecx
movl %eax,izistep
cmpl $0,%ecx
jle LNextSpan
LSpanLoop:
//
// set up the initial s/z, t/z, and 1/z on the FP stack, and generate the
// initial s and t values
//
// FIXME: pipeline FILD?
fildl sspan_t_v(%ebx)
fildl sspan_t_u(%ebx)
fld %st(1) // dv | du | dv
fmuls C(d_sdivzstepv) // dv*d_sdivzstepv | du | dv
fld %st(1) // du | dv*d_sdivzstepv | du | dv
fmuls C(d_sdivzstepu) // du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
fld %st(2) // du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
fmuls C(d_tdivzstepu) // du*d_tdivzstepu | du*d_sdivzstepu |
// dv*d_sdivzstepv | du | dv
fxch %st(1) // du*d_sdivzstepu | du*d_tdivzstepu |
// dv*d_sdivzstepv | du | dv
faddp %st(0),%st(2) // du*d_tdivzstepu |
// du*d_sdivzstepu + dv*d_sdivzstepv | du | dv
fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv |
// du*d_tdivzstepu | du | dv
fld %st(3) // dv | du*d_sdivzstepu + dv*d_sdivzstepv |
// du*d_tdivzstepu | du | dv
fmuls C(d_tdivzstepv) // dv*d_tdivzstepv |
// du*d_sdivzstepu + dv*d_sdivzstepv |
// du*d_tdivzstepu | du | dv
fxch %st(1) // du*d_sdivzstepu + dv*d_sdivzstepv |
// dv*d_tdivzstepv | du*d_tdivzstepu | du | dv
fadds C(d_sdivzorigin) // sdivz = d_sdivzorigin + dv*d_sdivzstepv +
// du*d_sdivzstepu; stays in %st(2) at end
fxch %st(4) // dv | dv*d_tdivzstepv | du*d_tdivzstepu | du |
// s/z
fmuls C(d_zistepv) // dv*d_zistepv | dv*d_tdivzstepv |
// du*d_tdivzstepu | du | s/z
fxch %st(1) // dv*d_tdivzstepv | dv*d_zistepv |
// du*d_tdivzstepu | du | s/z
faddp %st(0),%st(2) // dv*d_zistepv |
// dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z
fxch %st(2) // du | dv*d_tdivzstepv + du*d_tdivzstepu |
// dv*d_zistepv | s/z
fmuls C(d_zistepu) // du*d_zistepu |
// dv*d_tdivzstepv + du*d_tdivzstepu |
// dv*d_zistepv | s/z
fxch %st(1) // dv*d_tdivzstepv + du*d_tdivzstepu |
// du*d_zistepu | dv*d_zistepv | s/z
fadds C(d_tdivzorigin) // tdivz = d_tdivzorigin + dv*d_tdivzstepv +
// du*d_tdivzstepu; stays in %st(1) at end
fxch %st(2) // dv*d_zistepv | du*d_zistepu | t/z | s/z
faddp %st(0),%st(1) // dv*d_zistepv + du*d_zistepu | t/z | s/z
flds fp_64k // fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z
fxch %st(1) // dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z
fadds C(d_ziorigin) // zi = d_ziorigin + dv*d_zistepv +
// du*d_zistepu; stays in %st(0) at end
// 1/z | fp_64k | t/z | s/z
fld %st(0) // FIXME: get rid of stall on FMUL?
fmuls fp_64kx64k
fxch %st(1)
//
// calculate and clamp s & t
//
fdivr %st(0),%st(2) // 1/z | z*64k | t/z | s/z
fxch %st(1)
fistpl izi // 0.32 fixed-point 1/z
movl izi,%ebp
//
// set pz to point to the first z-buffer pixel in the span
//
rorl $16,%ebp // put upper 16 bits in low word
movl sspan_t_v(%ebx),%eax
movl %ebp,izi
movl sspan_t_u(%ebx),%ebp
imull C(d_zrowbytes)
shll $1,%ebp // a word per pixel
addl C(d_pzbuffer),%eax
addl %ebp,%eax
movl %eax,pz
//
// point %edi to the first pixel in the span
//
movl C(d_viewbuffer),%ebp
movl sspan_t_v(%ebx),%eax
pushl %ebx // preserve spans pointer
movl C(tadjust),%edx
movl C(sadjust),%esi
movl C(d_scantable)(,%eax,4),%edi // v * screenwidth
addl %ebp,%edi
movl sspan_t_u(%ebx),%ebp
addl %ebp,%edi // pdest = &pdestspan[scans->u];
//
// now start the FDIV for the end of the span
//
cmpl $8,%ecx
ja LSetupNotLast1
decl %ecx
jz LCleanup1 // if only one pixel, no need to start an FDIV
movl %ecx,spancountminus1
// finish up the s and t calcs
fxch %st(1) // z*64k | 1/z | t/z | s/z
fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z
fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z
fxch %st(1) // z*64k | s | 1/z | t/z | s/z
fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z
fxch %st(1) // s | t | 1/z | t/z | s/z
fistpl s // 1/z | t | t/z | s/z
fistpl t // 1/z | t/z | s/z
fildl spancountminus1
flds C(d_tdivzstepu) // _d_tdivzstepu | spancountminus1
flds C(d_zistepu) // _d_zistepu | _d_tdivzstepu | spancountminus1
fmul %st(2),%st(0) // _d_zistepu*scm1 | _d_tdivzstepu | scm1
fxch %st(1) // _d_tdivzstepu | _d_zistepu*scm1 | scm1
fmul %st(2),%st(0) // _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
fxch %st(2) // scm1 | _d_zistepu*scm1 | _d_tdivzstepu*scm1
fmuls C(d_sdivzstepu) // _d_sdivzstepu*scm1 | _d_zistepu*scm1 |
// _d_tdivzstepu*scm1
fxch %st(1) // _d_zistepu*scm1 | _d_sdivzstepu*scm1 |
// _d_tdivzstepu*scm1
faddp %st(0),%st(3) // _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
fxch %st(1) // _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
faddp %st(0),%st(3) // _d_sdivzstepu*scm1
faddp %st(0),%st(3)
flds fp_64k
fdiv %st(1),%st(0) // this is what we've gone to all this trouble to
// overlap
jmp LFDIVInFlight1
LCleanup1:
// finish up the s and t calcs
fxch %st(1) // z*64k | 1/z | t/z | s/z
fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z
fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z
fxch %st(1) // z*64k | s | 1/z | t/z | s/z
fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z
fxch %st(1) // s | t | 1/z | t/z | s/z
fistpl s // 1/z | t | t/z | s/z
fistpl t // 1/z | t/z | s/z
jmp LFDIVInFlight1
.align 4
LSetupNotLast1:
// finish up the s and t calcs
fxch %st(1) // z*64k | 1/z | t/z | s/z
fld %st(0) // z*64k | z*64k | 1/z | t/z | s/z
fmul %st(4),%st(0) // s | z*64k | 1/z | t/z | s/z
fxch %st(1) // z*64k | s | 1/z | t/z | s/z
fmul %st(3),%st(0) // t | s | 1/z | t/z | s/z
fxch %st(1) // s | t | 1/z | t/z | s/z
fistpl s // 1/z | t | t/z | s/z
fistpl t // 1/z | t/z | s/z
fadds zi8stepu
fxch %st(2)
fadds sdivz8stepu
fxch %st(2)
flds tdivz8stepu
faddp %st(0),%st(2)
flds fp_64k
fdiv %st(1),%st(0) // z = 1/1/z
// this is what we've gone to all this trouble to
// overlap
LFDIVInFlight1:
addl s,%esi
addl t,%edx
movl C(bbextents),%ebx
movl C(bbextentt),%ebp
cmpl %ebx,%esi
ja LClampHighOrLow0
LClampReentry0:
movl %esi,s
movl pbase,%ebx
shll $16,%esi
cmpl %ebp,%edx
movl %esi,sfracf
ja LClampHighOrLow1
LClampReentry1:
movl %edx,t
movl s,%esi // sfrac = scans->sfrac;
shll $16,%edx
movl t,%eax // tfrac = scans->tfrac;
sarl $16,%esi
movl %edx,tfracf
//
// calculate the texture starting address
//
sarl $16,%eax
addl %ebx,%esi
imull C(cachewidth),%eax // (tfrac >> 16) * cachewidth
addl %eax,%esi // psource = pbase + (sfrac >> 16) +
// ((tfrac >> 16) * cachewidth);
//
// determine whether last span or not
//
cmpl $8,%ecx
jna LLastSegment
//
// not the last segment; do full 8-wide segment
//
LNotLastSegment:
//
// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
// get there
//
// pick up after the FDIV that was left in flight previously
fld %st(0) // duplicate it
fmul %st(4),%st(0) // s = s/z * z
fxch %st(1)
fmul %st(3),%st(0) // t = t/z * z
fxch %st(1)
fistpl snext
fistpl tnext
movl snext,%eax
movl tnext,%edx
subl $8,%ecx // count off this segments' pixels
movl C(sadjust),%ebp
pushl %ecx // remember count of remaining pixels
movl C(tadjust),%ecx
addl %eax,%ebp
addl %edx,%ecx
movl C(bbextents),%eax
movl C(bbextentt),%edx
cmpl $2048,%ebp
jl LClampLow2
cmpl %eax,%ebp
ja LClampHigh2
LClampReentry2:
cmpl $2048,%ecx
jl LClampLow3
cmpl %edx,%ecx
ja LClampHigh3
LClampReentry3:
movl %ebp,snext
movl %ecx,tnext
subl s,%ebp
subl t,%ecx
//
// set up advancetable
//
movl %ecx,%eax
movl %ebp,%edx
sarl $19,%edx // sstep >>= 16;
movl C(cachewidth),%ebx
sarl $19,%eax // tstep >>= 16;
jz LIsZero
imull %ebx,%eax // (tstep >> 16) * cachewidth;
LIsZero:
addl %edx,%eax // add in sstep
// (tstep >> 16) * cachewidth + (sstep >> 16);
movl tfracf,%edx
movl %eax,advancetable+4 // advance base in t
addl %ebx,%eax // ((tstep >> 16) + 1) * cachewidth +
// (sstep >> 16);
shll $13,%ebp // left-justify sstep fractional part
movl %ebp,sstep
movl sfracf,%ebx
shll $13,%ecx // left-justify tstep fractional part
movl %eax,advancetable // advance extra in t
movl %ecx,tstep
movl pz,%ecx
movl izi,%ebp
cmpw (%ecx),%bp
jl Lp1
movb (%esi),%al // get first source texel
cmpb $(TRANSPARENT_COLOR),%al
jz Lp1
movw %bp,(%ecx)
movb %al,(%edi) // store first dest pixel
Lp1:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx // advance tfrac fractional part by tstep frac
sbbl %eax,%eax // turn tstep carry into -1 (0 if none)
addl sstep,%ebx // advance sfrac fractional part by sstep frac
adcl advancetable+4(,%eax,4),%esi // point to next source texel
cmpw 2(%ecx),%bp
jl Lp2
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp2
movw %bp,2(%ecx)
movb %al,1(%edi)
Lp2:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
cmpw 4(%ecx),%bp
jl Lp3
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp3
movw %bp,4(%ecx)
movb %al,2(%edi)
Lp3:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
cmpw 6(%ecx),%bp
jl Lp4
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp4
movw %bp,6(%ecx)
movb %al,3(%edi)
Lp4:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
cmpw 8(%ecx),%bp
jl Lp5
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp5
movw %bp,8(%ecx)
movb %al,4(%edi)
Lp5:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
//
// start FDIV for end of next segment in flight, so it can overlap
//
popl %eax
cmpl $8,%eax // more than one segment after this?
ja LSetupNotLast2 // yes
decl %eax
jz LFDIVInFlight2 // if only one pixel, no need to start an FDIV
movl %eax,spancountminus1
fildl spancountminus1
flds C(d_zistepu) // _d_zistepu | spancountminus1
fmul %st(1),%st(0) // _d_zistepu*scm1 | scm1
flds C(d_tdivzstepu) // _d_tdivzstepu | _d_zistepu*scm1 | scm1
fmul %st(2),%st(0) // _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
fxch %st(1) // _d_zistepu*scm1 | _d_tdivzstepu*scm1 | scm1
faddp %st(0),%st(3) // _d_tdivzstepu*scm1 | scm1
fxch %st(1) // scm1 | _d_tdivzstepu*scm1
fmuls C(d_sdivzstepu) // _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
fxch %st(1) // _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
faddp %st(0),%st(3) // _d_sdivzstepu*scm1
flds fp_64k // 64k | _d_sdivzstepu*scm1
fxch %st(1) // _d_sdivzstepu*scm1 | 64k
faddp %st(0),%st(4) // 64k
fdiv %st(1),%st(0) // this is what we've gone to all this trouble to
// overlap
jmp LFDIVInFlight2
.align 4
LSetupNotLast2:
fadds zi8stepu
fxch %st(2)
fadds sdivz8stepu
fxch %st(2)
flds tdivz8stepu
faddp %st(0),%st(2)
flds fp_64k
fdiv %st(1),%st(0) // z = 1/1/z
// this is what we've gone to all this trouble to
// overlap
LFDIVInFlight2:
pushl %eax
cmpw 10(%ecx),%bp
jl Lp6
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp6
movw %bp,10(%ecx)
movb %al,5(%edi)
Lp6:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
cmpw 12(%ecx),%bp
jl Lp7
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp7
movw %bp,12(%ecx)
movb %al,6(%edi)
Lp7:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
cmpw 14(%ecx),%bp
jl Lp8
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp8
movw %bp,14(%ecx)
movb %al,7(%edi)
Lp8:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
addl $8,%edi
addl $16,%ecx
movl %edx,tfracf
movl snext,%edx
movl %ebx,sfracf
movl tnext,%ebx
movl %edx,s
movl %ebx,t
movl %ecx,pz
movl %ebp,izi
popl %ecx // retrieve count
//
// determine whether last span or not
//
cmpl $8,%ecx // are there multiple segments remaining?
ja LNotLastSegment // yes
//
// last segment of scan
//
LLastSegment:
//
// advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
// get there. The number of pixels left is variable, and we want to land on the
// last pixel, not step one past it, so we can't run into arithmetic problems
//
testl %ecx,%ecx
jz LNoSteps // just draw the last pixel and we're done
// pick up after the FDIV that was left in flight previously
fld %st(0) // duplicate it
fmul %st(4),%st(0) // s = s/z * z
fxch %st(1)
fmul %st(3),%st(0) // t = t/z * z
fxch %st(1)
fistpl snext
fistpl tnext
movl C(tadjust),%ebx
movl C(sadjust),%eax
addl snext,%eax
addl tnext,%ebx
movl C(bbextents),%ebp
movl C(bbextentt),%edx
cmpl $2048,%eax
jl LClampLow4
cmpl %ebp,%eax
ja LClampHigh4
LClampReentry4:
movl %eax,snext
cmpl $2048,%ebx
jl LClampLow5
cmpl %edx,%ebx
ja LClampHigh5
LClampReentry5:
cmpl $1,%ecx // don't bother
je LOnlyOneStep // if two pixels in segment, there's only one step,
// of the segment length
subl s,%eax
subl t,%ebx
addl %eax,%eax // convert to 15.17 format so multiply by 1.31
addl %ebx,%ebx // reciprocal yields 16.48
imull reciprocal_table-8(,%ecx,4) // sstep = (snext - s) / (spancount-1)
movl %edx,%ebp
movl %ebx,%eax
imull reciprocal_table-8(,%ecx,4) // tstep = (tnext - t) / (spancount-1)
LSetEntryvec:
//
// set up advancetable
//
movl spr8entryvec_table(,%ecx,4),%ebx
movl %edx,%eax
pushl %ebx // entry point into code for RET later
movl %ebp,%ecx
sarl $16,%ecx // sstep >>= 16;
movl C(cachewidth),%ebx
sarl $16,%edx // tstep >>= 16;
jz LIsZeroLast
imull %ebx,%edx // (tstep >> 16) * cachewidth;
LIsZeroLast:
addl %ecx,%edx // add in sstep
// (tstep >> 16) * cachewidth + (sstep >> 16);
movl tfracf,%ecx
movl %edx,advancetable+4 // advance base in t
addl %ebx,%edx // ((tstep >> 16) + 1) * cachewidth +
// (sstep >> 16);
shll $16,%ebp // left-justify sstep fractional part
movl sfracf,%ebx
shll $16,%eax // left-justify tstep fractional part
movl %edx,advancetable // advance extra in t
movl %eax,tstep
movl %ebp,sstep
movl %ecx,%edx
movl pz,%ecx
movl izi,%ebp
ret // jump to the number-of-pixels handler
//----------------------------------------
LNoSteps:
movl pz,%ecx
subl $7,%edi // adjust for hardwired offset
subl $14,%ecx
jmp LEndSpan
LOnlyOneStep:
subl s,%eax
subl t,%ebx
movl %eax,%ebp
movl %ebx,%edx
jmp LSetEntryvec
//----------------------------------------
.globl Spr8Entry2_8
Spr8Entry2_8:
subl $6,%edi // adjust for hardwired offsets
subl $12,%ecx
movb (%esi),%al
jmp LLEntry2_8
//----------------------------------------
.globl Spr8Entry3_8
Spr8Entry3_8:
subl $5,%edi // adjust for hardwired offsets
subl $10,%ecx
jmp LLEntry3_8
//----------------------------------------
.globl Spr8Entry4_8
Spr8Entry4_8:
subl $4,%edi // adjust for hardwired offsets
subl $8,%ecx
jmp LLEntry4_8
//----------------------------------------
.globl Spr8Entry5_8
Spr8Entry5_8:
subl $3,%edi // adjust for hardwired offsets
subl $6,%ecx
jmp LLEntry5_8
//----------------------------------------
.globl Spr8Entry6_8
Spr8Entry6_8:
subl $2,%edi // adjust for hardwired offsets
subl $4,%ecx
jmp LLEntry6_8
//----------------------------------------
.globl Spr8Entry7_8
Spr8Entry7_8:
decl %edi // adjust for hardwired offsets
subl $2,%ecx
jmp LLEntry7_8
//----------------------------------------
.globl Spr8Entry8_8
Spr8Entry8_8:
cmpw (%ecx),%bp
jl Lp9
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp9
movw %bp,(%ecx)
movb %al,(%edi)
Lp9:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
LLEntry7_8:
cmpw 2(%ecx),%bp
jl Lp10
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp10
movw %bp,2(%ecx)
movb %al,1(%edi)
Lp10:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
LLEntry6_8:
cmpw 4(%ecx),%bp
jl Lp11
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp11
movw %bp,4(%ecx)
movb %al,2(%edi)
Lp11:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
LLEntry5_8:
cmpw 6(%ecx),%bp
jl Lp12
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp12
movw %bp,6(%ecx)
movb %al,3(%edi)
Lp12:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
LLEntry4_8:
cmpw 8(%ecx),%bp
jl Lp13
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp13
movw %bp,8(%ecx)
movb %al,4(%edi)
Lp13:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
LLEntry3_8:
cmpw 10(%ecx),%bp
jl Lp14
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp14
movw %bp,10(%ecx)
movb %al,5(%edi)
Lp14:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
LLEntry2_8:
cmpw 12(%ecx),%bp
jl Lp15
movb (%esi),%al
cmpb $(TRANSPARENT_COLOR),%al
jz Lp15
movw %bp,12(%ecx)
movb %al,6(%edi)
Lp15:
addl izistep,%ebp
adcl $0,%ebp
addl tstep,%edx
sbbl %eax,%eax
addl sstep,%ebx
adcl advancetable+4(,%eax,4),%esi
LEndSpan:
cmpw 14(%ecx),%bp
jl Lp16
movb (%esi),%al // load first texel in segment
cmpb $(TRANSPARENT_COLOR),%al
jz Lp16
movw %bp,14(%ecx)
movb %al,7(%edi)
Lp16:
//
// clear s/z, t/z, 1/z from FP stack
//
fstp %st(0)
fstp %st(0)
fstp %st(0)
popl %ebx // restore spans pointer
LNextSpan:
addl $(sspan_t_size),%ebx // point to next span
movl sspan_t_count(%ebx),%ecx
cmpl $0,%ecx // any more spans?
jg LSpanLoop // yes
jz LNextSpan // yes, but this one's empty
popl %ebx // restore register variables
popl %esi
popl %edi
popl %ebp // restore the caller's stack frame
ret
#endif // id386

926
engine/sw/d_sprite.c Normal file
View file

@ -0,0 +1,926 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_sprite.c: software top-level rasterization driver module for drawing
// sprites
#include "quakedef.h"
#include "d_local.h"
static int sprite_height;
static int minindex, maxindex;
static sspan_t *sprite_spans;
#if !id386
/*
=====================
D_SpriteDrawSpans
=====================
*/
void D_SpriteDrawSpans (sspan_t *pspan)
{
int count, spancount, izistep;
int izi;
qbyte *pbase, *pdest;
fixed16_t s, t, snext, tnext, sstep, tstep;
float sdivz, tdivz, zi, z, du, dv, spancountminus1;
float sdivz8stepu, tdivz8stepu, zi8stepu;
qbyte btemp;
short *pz;
sstep = 0; // keep compiler happy
tstep = 0; // ditto
pbase = cacheblock;
sdivz8stepu = d_sdivzstepu * 8;
tdivz8stepu = d_tdivzstepu * 8;
zi8stepu = d_zistepu * 8;
// we count on FP exceptions being turned off to avoid range problems
izistep = (int)(d_zistepu * 0x8000 * 0x10000);
do
{
pdest = (qbyte *)d_viewbuffer + r_pixbytes*((screenwidth * pspan->v) + pspan->u);
pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
count = pspan->count;
if (count <= 0)
goto NextSpan;
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
du = (float)pspan->u;
dv = (float)pspan->v;
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
// we count on FP exceptions being turned off to avoid range problems
izi = (int)(zi * 0x8000 * 0x10000);
s = (int)(sdivz * z) + sadjust;
if (s > bbextents)
s = bbextents;
else if (s < 0)
s = 0;
t = (int)(tdivz * z) + tadjust;
if (t > bbextentt)
t = bbextentt;
else if (t < 0)
t = 0;
do
{
// calculate s and t at the far end of the span
if (count >= 8)
spancount = 8;
else
spancount = count;
count -= spancount;
if (count)
{
// calculate s/z, t/z, zi->fixed s and t at far end of span,
// calculate s and t steps across span by shifting
sdivz += sdivz8stepu;
tdivz += tdivz8stepu;
zi += zi8stepu;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
snext = (int)(sdivz * z) + sadjust;
if (snext > bbextents)
snext = bbextents;
else if (snext < 8)
snext = 8; // prevent round-off error on <0 steps from
// from causing overstepping & running off the
// edge of the texture
tnext = (int)(tdivz * z) + tadjust;
if (tnext > bbextentt)
tnext = bbextentt;
else if (tnext < 8)
tnext = 8; // guard against round-off error on <0 steps
sstep = (snext - s) >> 3;
tstep = (tnext - t) >> 3;
}
else
{
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
// can't step off polygon), clamp, calculate s and t steps across
// span by division, biasing steps low so we don't run off the
// texture
spancountminus1 = (float)(spancount - 1);
sdivz += d_sdivzstepu * spancountminus1;
tdivz += d_tdivzstepu * spancountminus1;
zi += d_zistepu * spancountminus1;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
snext = (int)(sdivz * z) + sadjust;
if (snext > bbextents)
snext = bbextents;
else if (snext < 8)
snext = 8; // prevent round-off error on <0 steps from
// from causing overstepping & running off the
// edge of the texture
tnext = (int)(tdivz * z) + tadjust;
if (tnext > bbextentt)
tnext = bbextentt;
else if (tnext < 8)
tnext = 8; // guard against round-off error on <0 steps
if (spancount > 1)
{
sstep = (snext - s) / (spancount - 1);
tstep = (tnext - t) / (spancount - 1);
}
}
do
{
btemp = *(pbase + ((s >> 16) + (t >> 16) * cachewidth));
if (btemp != 255)
{
if (*pz <= (izi >> 16))
{
*pz = izi >> 16;
*pdest = btemp;
}
}
izi += izistep;
pdest++;
pz++;
s += sstep;
t += tstep;
} while (--spancount > 0);
s = snext;
t = tnext;
} while (count > 0);
NextSpan:
pspan++;
} while (pspan->count != DS_SPAN_LIST_END);
}
#endif
void D_SpriteDrawSpans16 (sspan_t *pspan)
{
int count, spancount, izistep;
int izi;
unsigned short *pbase, *pdest;
fixed16_t s, t, snext, tnext, sstep, tstep;
float sdivz, tdivz, zi, z, du, dv, spancountminus1;
float sdivz8stepu, tdivz8stepu, zi8stepu;
unsigned short btemp;
short *pz;
sstep = 0; // keep compiler happy
tstep = 0; // ditto
pbase = (unsigned short *)cacheblock;
sdivz8stepu = d_sdivzstepu * 8;
tdivz8stepu = d_tdivzstepu * 8;
zi8stepu = d_zistepu * 8;
// we count on FP exceptions being turned off to avoid range problems
izistep = (int)(d_zistepu * 0x8000 * 0x10000);
do
{
pdest = (unsigned short *)d_viewbuffer + ((screenwidth * pspan->v) + pspan->u);
pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
count = pspan->count;
if (count <= 0)
goto NextSpan;
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
du = (float)pspan->u;
dv = (float)pspan->v;
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
// we count on FP exceptions being turned off to avoid range problems
izi = (int)(zi * 0x8000 * 0x10000);
s = (int)(sdivz * z) + sadjust;
if (s > bbextents)
s = bbextents;
else if (s < 0)
s = 0;
t = (int)(tdivz * z) + tadjust;
if (t > bbextentt)
t = bbextentt;
else if (t < 0)
t = 0;
do
{
// calculate s and t at the far end of the span
if (count >= 8)
spancount = 8;
else
spancount = count;
count -= spancount;
if (count)
{
// calculate s/z, t/z, zi->fixed s and t at far end of span,
// calculate s and t steps across span by shifting
sdivz += sdivz8stepu;
tdivz += tdivz8stepu;
zi += zi8stepu;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
snext = (int)(sdivz * z) + sadjust;
if (snext > bbextents)
snext = bbextents;
else if (snext < 8)
snext = 8; // prevent round-off error on <0 steps from
// from causing overstepping & running off the
// edge of the texture
tnext = (int)(tdivz * z) + tadjust;
if (tnext > bbextentt)
tnext = bbextentt;
else if (tnext < 8)
tnext = 8; // guard against round-off error on <0 steps
sstep = (snext - s) >> 3;
tstep = (tnext - t) >> 3;
}
else
{
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
// can't step off polygon), clamp, calculate s and t steps across
// span by division, biasing steps low so we don't run off the
// texture
spancountminus1 = (float)(spancount - 1);
sdivz += d_sdivzstepu * spancountminus1;
tdivz += d_tdivzstepu * spancountminus1;
zi += d_zistepu * spancountminus1;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
snext = (int)(sdivz * z) + sadjust;
if (snext > bbextents)
snext = bbextents;
else if (snext < 8)
snext = 8; // prevent round-off error on <0 steps from
// from causing overstepping & running off the
// edge of the texture
tnext = (int)(tdivz * z) + tadjust;
if (tnext > bbextentt)
tnext = bbextentt;
else if (tnext < 8)
tnext = 8; // guard against round-off error on <0 steps
if (spancount > 1)
{
sstep = (snext - s) / (spancount - 1);
tstep = (tnext - t) / (spancount - 1);
}
}
do
{
btemp = *(pbase + ((s >> 16) + (t >> 16) * cachewidth));
if (btemp != 0xffff)
{
if (*pz <= (izi >> 16))
{
*pz = izi >> 16;
*pdest = btemp;
}
}
izi += izistep;
pdest++;
pz++;
s += sstep;
t += tstep;
} while (--spancount > 0);
s = snext;
t = tnext;
} while (count > 0);
NextSpan:
pspan++;
} while (pspan->count != DS_SPAN_LIST_END);
}
void D_SpriteDrawSpans32 (sspan_t *pspan)
{
int count, spancount, izistep;
int izi;
unsigned int *pbase, *pdest;
fixed16_t s, t, snext, tnext, sstep, tstep;
float sdivz, tdivz, zi, z, du, dv, spancountminus1;
float sdivz8stepu, tdivz8stepu, zi8stepu;
unsigned int itemp;
qbyte *pbtemp, *pbdest, alpha;
short *pz;
sstep = 0; // keep compiler happy
tstep = 0; // ditto
pbase = (unsigned int*)cacheblock;
sdivz8stepu = d_sdivzstepu * 8;
tdivz8stepu = d_tdivzstepu * 8;
zi8stepu = d_zistepu * 8;
// we count on FP exceptions being turned off to avoid range problems
izistep = (int)(d_zistepu * 0x8000 * 0x10000);
do
{
pdest = (unsigned int *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
count = pspan->count;
if (count <= 0)
goto NextSpan;
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
du = (float)pspan->u;
dv = (float)pspan->v;
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
// we count on FP exceptions being turned off to avoid range problems
izi = (int)(zi * 0x8000 * 0x10000);
s = (int)(sdivz * z) + sadjust;
if (s > bbextents)
s = bbextents;
else if (s < 0)
s = 0;
t = (int)(tdivz * z) + tadjust;
if (t > bbextentt)
t = bbextentt;
else if (t < 0)
t = 0;
do
{
// calculate s and t at the far end of the span
if (count >= 8)
spancount = 8;
else
spancount = count;
count -= spancount;
if (count)
{
// calculate s/z, t/z, zi->fixed s and t at far end of span,
// calculate s and t steps across span by shifting
sdivz += sdivz8stepu;
tdivz += tdivz8stepu;
zi += zi8stepu;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
snext = (int)(sdivz * z) + sadjust;
if (snext > bbextents)
snext = bbextents;
else if (snext < 8)
snext = 8; // prevent round-off error on <0 steps from
// from causing overstepping & running off the
// edge of the texture
tnext = (int)(tdivz * z) + tadjust;
if (tnext > bbextentt)
tnext = bbextentt;
else if (tnext < 8)
tnext = 8; // guard against round-off error on <0 steps
sstep = (snext - s) >> 3;
tstep = (tnext - t) >> 3;
}
else
{
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
// can't step off polygon), clamp, calculate s and t steps across
// span by division, biasing steps low so we don't run off the
// texture
spancountminus1 = (float)(spancount - 1);
sdivz += d_sdivzstepu * spancountminus1;
tdivz += d_tdivzstepu * spancountminus1;
zi += d_zistepu * spancountminus1;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
snext = (int)(sdivz * z) + sadjust;
if (snext > bbextents)
snext = bbextents;
else if (snext < 8)
snext = 8; // prevent round-off error on <0 steps from
// from causing overstepping & running off the
// edge of the texture
tnext = (int)(tdivz * z) + tadjust;
if (tnext > bbextentt)
tnext = bbextentt;
else if (tnext < 8)
tnext = 8; // guard against round-off error on <0 steps
if (spancount > 1)
{
sstep = (snext - s) / (spancount - 1);
tstep = (tnext - t) / (spancount - 1);
}
}
do
{
itemp = *(pbase + ((s >> 16) + (t >> 16) * cachewidth));
if ((alpha = itemp>>24))
{
alpha = 128;
if (*pz <= (izi >> 16))
{
*pz = izi >> 16;
pbtemp = (qbyte *)&itemp;
pbdest = (qbyte *)pdest;
pbdest[0] = (pbdest[0]*(255-alpha) + pbtemp[0]*alpha)/255;
pbdest[1] = (pbdest[1]*(255-alpha) + pbtemp[1]*alpha)/255;
pbdest[2] = (pbdest[2]*(255-alpha) + pbtemp[2]*alpha)/255;
}
}
izi += izistep;
pdest++;
pz++;
s += sstep;
t += tstep;
} while (--spancount > 0);
s = snext;
t = tnext;
} while (count > 0);
NextSpan:
pspan++;
} while (pspan->count != DS_SPAN_LIST_END);
}
#ifdef PEXT_TRANS
void D_SpriteDrawSpansTrans (sspan_t *pspan)
{
int count, spancount, izistep;
int izi;
qbyte *pbase, *pdest;
fixed16_t s, t, snext, tnext, sstep, tstep;
float sdivz, tdivz, zi, z, du, dv, spancountminus1;
float sdivz8stepu, tdivz8stepu, zi8stepu;
qbyte btemp;
short *pz;
sstep = 0; // keep compiler happy
tstep = 0; // ditto
pbase = cacheblock;
sdivz8stepu = d_sdivzstepu * 8;
tdivz8stepu = d_tdivzstepu * 8;
zi8stepu = d_zistepu * 8;
// we count on FP exceptions being turned off to avoid range problems
izistep = (int)(d_zistepu * 0x8000 * 0x10000);
do
{
pdest = (qbyte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
count = pspan->count;
if (count <= 0)
goto NextSpan;
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
du = (float)pspan->u;
dv = (float)pspan->v;
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
// we count on FP exceptions being turned off to avoid range problems
izi = (int)(zi * 0x8000 * 0x10000);
s = (int)(sdivz * z) + sadjust;
if (s > bbextents)
s = bbextents;
else if (s < 0)
s = 0;
t = (int)(tdivz * z) + tadjust;
if (t > bbextentt)
t = bbextentt;
else if (t < 0)
t = 0;
do
{
// calculate s and t at the far end of the span
if (count >= 8)
spancount = 8;
else
spancount = count;
count -= spancount;
if (count)
{
// calculate s/z, t/z, zi->fixed s and t at far end of span,
// calculate s and t steps across span by shifting
sdivz += sdivz8stepu;
tdivz += tdivz8stepu;
zi += zi8stepu;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
snext = (int)(sdivz * z) + sadjust;
if (snext > bbextents)
snext = bbextents;
else if (snext < 8)
snext = 8; // prevent round-off error on <0 steps from
// from causing overstepping & running off the
// edge of the texture
tnext = (int)(tdivz * z) + tadjust;
if (tnext > bbextentt)
tnext = bbextentt;
else if (tnext < 8)
tnext = 8; // guard against round-off error on <0 steps
sstep = (snext - s) >> 3;
tstep = (tnext - t) >> 3;
}
else
{
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
// can't step off polygon), clamp, calculate s and t steps across
// span by division, biasing steps low so we don't run off the
// texture
spancountminus1 = (float)(spancount - 1);
sdivz += d_sdivzstepu * spancountminus1;
tdivz += d_tdivzstepu * spancountminus1;
zi += d_zistepu * spancountminus1;
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
snext = (int)(sdivz * z) + sadjust;
if (snext > bbextents)
snext = bbextents;
else if (snext < 8)
snext = 8; // prevent round-off error on <0 steps from
// from causing overstepping & running off the
// edge of the texture
tnext = (int)(tdivz * z) + tadjust;
if (tnext > bbextentt)
tnext = bbextentt;
else if (tnext < 8)
tnext = 8; // guard against round-off error on <0 steps
if (spancount > 1)
{
sstep = (snext - s) / (spancount - 1);
tstep = (tnext - t) / (spancount - 1);
}
}
do
{
btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
if (btemp != 255)
{
if (*pz <= (izi >> 16))
{
*pz = izi >> 16;
*pdest = Trans(*pdest, btemp);
}
}
izi += izistep;
pdest++;
pz++;
s += sstep;
t += tstep;
} while (--spancount > 0);
s = snext;
t = tnext;
} while (count > 0);
NextSpan:
pspan++;
} while (pspan->count != DS_SPAN_LIST_END);
}
#endif
/*
=====================
D_SpriteScanLeftEdge
=====================
*/
void D_SpriteScanLeftEdge (void)
{
int i, v, itop, ibottom, lmaxindex;
emitpoint_t *pvert, *pnext;
sspan_t *pspan;
float du, dv, vtop, vbottom, slope;
fixed16_t u, u_step;
pspan = sprite_spans;
i = minindex;
if (i == 0)
i = r_spritedesc.nump;
lmaxindex = maxindex;
if (lmaxindex == 0)
lmaxindex = r_spritedesc.nump;
vtop = ceil (r_spritedesc.pverts[i].v);
do
{
pvert = &r_spritedesc.pverts[i];
pnext = pvert - 1;
vbottom = ceil (pnext->v);
if (vtop < vbottom)
{
du = pnext->u - pvert->u;
dv = pnext->v - pvert->v;
slope = du / dv;
u_step = (int)(slope * 0x10000);
// adjust u to ceil the integer portion
u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
(0x10000 - 1);
itop = (int)vtop;
ibottom = (int)vbottom;
for (v=itop ; v<ibottom ; v++)
{
pspan->u = u >> 16;
pspan->v = v;
u += u_step;
pspan++;
}
}
vtop = vbottom;
i--;
if (i == 0)
i = r_spritedesc.nump;
} while (i != lmaxindex);
}
/*
=====================
D_SpriteScanRightEdge
=====================
*/
void D_SpriteScanRightEdge (void)
{
int i, v, itop, ibottom;
emitpoint_t *pvert, *pnext;
sspan_t *pspan;
float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
fixed16_t u, u_step;
pspan = sprite_spans;
i = minindex;
vvert = r_spritedesc.pverts[i].v;
if (vvert < r_refdef.fvrecty_adj)
vvert = r_refdef.fvrecty_adj;
if (vvert > r_refdef.fvrectbottom_adj)
vvert = r_refdef.fvrectbottom_adj;
vtop = ceil (vvert);
do
{
pvert = &r_spritedesc.pverts[i];
pnext = pvert + 1;
vnext = pnext->v;
if (vnext < r_refdef.fvrecty_adj)
vnext = r_refdef.fvrecty_adj;
if (vnext > r_refdef.fvrectbottom_adj)
vnext = r_refdef.fvrectbottom_adj;
vbottom = ceil (vnext);
if (vtop < vbottom)
{
uvert = pvert->u;
if (uvert < r_refdef.fvrectx_adj)
uvert = r_refdef.fvrectx_adj;
if (uvert > r_refdef.fvrectright_adj)
uvert = r_refdef.fvrectright_adj;
unext = pnext->u;
if (unext < r_refdef.fvrectx_adj)
unext = r_refdef.fvrectx_adj;
if (unext > r_refdef.fvrectright_adj)
unext = r_refdef.fvrectright_adj;
du = unext - uvert;
dv = vnext - vvert;
slope = du / dv;
u_step = (int)(slope * 0x10000);
// adjust u to ceil the integer portion
u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
(0x10000 - 1);
itop = (int)vtop;
ibottom = (int)vbottom;
for (v=itop ; v<ibottom ; v++)
{
pspan->count = (u >> 16) - pspan->u;
u += u_step;
pspan++;
}
}
vtop = vbottom;
vvert = vnext;
i++;
if (i == r_spritedesc.nump)
i = 0;
} while (i != maxindex);
pspan->count = DS_SPAN_LIST_END; // mark the end of the span list
}
/*
=====================
D_SpriteCalculateGradients
=====================
*/
void D_SpriteCalculateGradients (void)
{
vec3_t p_normal, p_saxis, p_taxis, p_temp1;
float distinv;
TransformVector (r_spritedesc.vpn, p_normal);
TransformVector (r_spritedesc.vright, p_saxis);
TransformVector (r_spritedesc.vup, p_taxis);
VectorInverse (p_taxis);
distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
d_sdivzstepu = p_saxis[0] * xscaleinv;
d_tdivzstepu = p_taxis[0] * xscaleinv;
d_sdivzstepv = -p_saxis[1] * yscaleinv;
d_tdivzstepv = -p_taxis[1] * yscaleinv;
d_zistepu = p_normal[0] * xscaleinv * distinv;
d_zistepv = -p_normal[1] * yscaleinv * distinv;
d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu -
ycenter * d_sdivzstepv;
d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu -
ycenter * d_tdivzstepv;
d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu -
ycenter * d_zistepv;
TransformVector (modelorg, p_temp1);
sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
(-(cachewidth >> 1) << 16);
tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
(-(sprite_height >> 1) << 16);
// -1 (-epsilon) so we never wander off the edge of the texture
bbextents = (cachewidth << 16) - 1;
bbextentt = (sprite_height << 16) - 1;
}
/*
=====================
D_DrawSprite
=====================
*/
void D_DrawSprite (void)
{
int i, nump;
float ymin, ymax;
emitpoint_t *pverts;
sspan_t spans[MAXHEIGHT+1];
sprite_spans = spans;
// find the top and bottom vertices, and make sure there's at least one scan to
// draw
ymin = 999999.9;
ymax = -999999.9;
pverts = r_spritedesc.pverts;
for (i=0 ; i<r_spritedesc.nump ; i++)
{
if (pverts->v < ymin)
{
ymin = pverts->v;
minindex = i;
}
if (pverts->v > ymax)
{
ymax = pverts->v;
maxindex = i;
}
pverts++;
}
ymin = ceil (ymin);
ymax = ceil (ymax);
if (ymin >= ymax)
return; // doesn't cross any scans at all
cachewidth = r_spritedesc.pspriteframe->width;
sprite_height = r_spritedesc.pspriteframe->height;
cacheblock = (qbyte *)&r_spritedesc.pspriteframe->pixels[0];
// copy the first vertex to the last vertex, so we don't have to deal with
// wrapping
nump = r_spritedesc.nump;
pverts = r_spritedesc.pverts;
pverts[nump] = pverts[0];
D_SpriteCalculateGradients ();
D_SpriteScanLeftEdge ();
D_SpriteScanRightEdge ();
#ifndef PEXT_TRANS
D_SpriteDrawSpans (sprite_spans);
#else
if (r_pixbytes == 4)
D_SpriteDrawSpans32 (sprite_spans);
else if (r_pixbytes == 2)
D_SpriteDrawSpans16 (sprite_spans);
else //1
{
if (currententity->alpha>=0.9)
D_SpriteDrawSpans (sprite_spans);
else
{
Set_TransLevelF(currententity->alpha);
D_SpriteDrawSpansTrans (sprite_spans);
}
}
#endif
}

351
engine/sw/d_surf.c Normal file
View file

@ -0,0 +1,351 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_surf.c: rasterization driver surface heap manager
#include "quakedef.h"
#include "d_local.h"
#include "r_local.h"
float surfscale;
qboolean r_cache_thrash; // set if surface cache is thrashing
int r_flushcache;
int sc_size;
surfcache_t *sc_rover, *sc_base;
#define GUARDSIZE 4
int D_SurfaceCacheForRes (int width, int height, int bpp)
{
int size, pix;
if (COM_CheckParm ("-surfcachesize"))
{
size = Q_atoi(com_argv[COM_CheckParm("-surfcachesize")+1]) * 1024;
return size;
}
size = 4096*1024;//SURFCACHE_SIZE_AT_320X200;
pix = width*height;
if (pix > 64000)
size += (pix-64000)*4;
if (bpp)
return size*bpp;
return size;
}
void D_CheckCacheGuard (void)
{
qbyte *s;
int i;
s = (qbyte *)sc_base + sc_size;
for (i=0 ; i<GUARDSIZE ; i++)
if (s[i] != (qbyte)i)
Sys_Error ("D_CheckCacheGuard: failed");
}
void D_ClearCacheGuard (void)
{
qbyte *s;
int i;
s = (qbyte *)sc_base + sc_size;
for (i=0 ; i<GUARDSIZE ; i++)
s[i] = (qbyte)i;
}
/*
================
D_InitCaches
================
*/
void D_InitCaches (void *buffer, int size)
{
// if (!msg_suppress_1)
// Con_Printf ("%ik surface cache\n", size/1024);
sc_size = size - GUARDSIZE;
sc_base = (surfcache_t *)buffer;
sc_rover = sc_base;
sc_base->next = NULL;
sc_base->owner = NULL;
sc_base->size = sc_size;
D_ClearCacheGuard ();
}
/*
==================
D_FlushCaches
==================
*/
void D_FlushCaches (void)
{
surfcache_t *c;
if (!sc_base)
return;
for (c = sc_base ; c ; c = c->next)
{
if (c->owner)
*c->owner = NULL;
}
sc_rover = sc_base;
sc_base->next = NULL;
sc_base->owner = NULL;
sc_base->size = sc_size;
}
/*
=================
D_SCAlloc
=================
*/
surfcache_t *D_SCAlloc (int width, int bpp, int size)
{
surfcache_t *new;
qboolean wrapped_this_time;
// if ((width < 0) || (width > 256))
// Sys_Error ("D_SCAlloc: bad cache width %d\n", width);
// if ((size <= 0) || (size > 0x10000*bpp))
// Sys_Error ("D_SCAlloc: bad cache size %d\n", size);
#ifdef __alpha__
size = (int)((long)&((surfcache_t *)0)->data[size]);
#else
size = (int)&((surfcache_t *)0)->data[size];
#endif
size = (size + 3) & ~3;
if (size > sc_size)
Sys_Error ("D_SCAlloc: %i > cache size",size);
// if there is not size bytes after the rover, reset to the start
wrapped_this_time = false;
if ( !sc_rover || (qbyte *)sc_rover - (qbyte *)sc_base > sc_size - size)
{
if (sc_rover)
{
wrapped_this_time = true;
}
sc_rover = sc_base;
}
// colect and free surfcache_t blocks until the rover block is large enough
new = sc_rover;
if (sc_rover->owner)
*sc_rover->owner = NULL;
while (new->size < size)
{
// free another
sc_rover = sc_rover->next;
if (!sc_rover)
Sys_Error ("D_SCAlloc: hit the end of memory");
if (sc_rover->owner)
*sc_rover->owner = NULL;
new->size += sc_rover->size;
new->next = sc_rover->next;
}
// create a fragment out of any leftovers
if (new->size - size > 256)
{
sc_rover = (surfcache_t *)( (qbyte *)new + size);
sc_rover->size = new->size - size;
sc_rover->next = new->next;
sc_rover->width = 0;
sc_rover->owner = NULL;
new->next = sc_rover;
new->size = size;
}
else
sc_rover = new->next;
new->width = width;
// DEBUG
if (width > 0)
new->height = (size - sizeof(*new) + sizeof(new->data)) / (width*bpp);
new->bytesperpix = bpp;
new->owner = NULL; // should be set properly after return
if (d_roverwrapped)
{
if (wrapped_this_time || (sc_rover >= d_initial_rover))
r_cache_thrash = true;
}
else if (wrapped_this_time)
{
d_roverwrapped = true;
}
D_CheckCacheGuard (); // DEBUG
return new;
}
/*
=================
D_SCDump
=================
*/
void D_SCDump (void)
{
surfcache_t *test;
for (test = sc_base ; test ; test = test->next)
{
if (test == sc_rover)
Sys_Printf ("ROVER:\n");
Sys_Printf ("%p : %i bytes %i width\n",test, test->size, test->width);
}
}
//=============================================================================
// if the num is not a power of 2, assume it will not repeat
int MaskForNum (int num)
{
if (num==128)
return 127;
if (num==64)
return 63;
if (num==32)
return 31;
if (num==16)
return 15;
return 255;
}
int D_log2 (int num)
{
int c;
c = 0;
while (num>>=1)
c++;
return c;
}
//=============================================================================
/*
================
D_CacheSurface
================
*/
surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
{
surfcache_t *cache;
int bpp;
//
// if the surface is animating or flashing, flush the cache
//
r_drawsurf.texture = SWR_TextureAnimation (surface->texinfo->texture);
r_drawsurf.lightadj[0] = d_lightstylevalue[surface->styles[0]];
r_drawsurf.lightadj[1] = d_lightstylevalue[surface->styles[1]];
r_drawsurf.lightadj[2] = d_lightstylevalue[surface->styles[2]];
r_drawsurf.lightadj[3] = d_lightstylevalue[surface->styles[3]];
//
// see if the cache holds apropriate data
//
cache = surface->cachespots[miplevel];
if (cache && !cache->dlight && surface->dlightframe != r_framecount
&& cache->texture == r_drawsurf.texture && cache->fcache == r_flushcache //extra part added to flush caches over a group of frames on palette change...
&& cache->lightadj[0] == r_drawsurf.lightadj[0]
&& cache->lightadj[1] == r_drawsurf.lightadj[1]
&& cache->lightadj[2] == r_drawsurf.lightadj[2]
&& cache->lightadj[3] == r_drawsurf.lightadj[3] )
return cache;
//
// determine shape of surface
//
surfscale = 1.0 / (1<<miplevel);
r_drawsurf.surfmip = miplevel;
r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
r_drawsurf.rowbytes = r_drawsurf.surfwidth;
r_drawsurf.surfheight = surface->extents[1] >> miplevel;
bpp = r_pixbytes;
//
// allocate memory if needed
//
if (!cache) // if a texture just animated, don't reallocate it
{
cache = D_SCAlloc (r_drawsurf.surfwidth, bpp,
r_drawsurf.surfwidth * r_drawsurf.surfheight * bpp);
surface->cachespots[miplevel] = cache;
cache->owner = &surface->cachespots[miplevel];
cache->mipscale = surfscale;
}
if (surface->dlightframe == r_framecount)
cache->dlight = 1;
else
cache->dlight = 0;
cache->fcache = r_flushcache;
r_drawsurf.surfdat = (pixel_t *)cache->data;
cache->texture = r_drawsurf.texture;
cache->lightadj[0] = r_drawsurf.lightadj[0];
cache->lightadj[1] = r_drawsurf.lightadj[1];
cache->lightadj[2] = r_drawsurf.lightadj[2];
cache->lightadj[3] = r_drawsurf.lightadj[3];
//
// draw and light the surface texture
//
r_drawsurf.surf = surface;
c_surf++;
if (cache->bytesperpix==4 && r_usinglits)
R_DrawSurface32 ();
else
R_DrawSurface ();
return surface->cachespots[miplevel];
}

180
engine/sw/d_trans.c Normal file
View file

@ -0,0 +1,180 @@
#include "quakedef.h"
#include "d_local.h"
#include "r_local.h"
#ifdef PEXT_TRANS
int t_numtables;
qbyte p1multitable[] = {1, 99, 49, 97, 48, 19, 47, 93, 23, 91, 9, 89, 22, 87, 43, 17, 21, 83, 41, 81, 4, 79, 39, 77, 19, 3, 37, 73, 18, 71, 7, 69, 17, 67, 33, 13, 16, 63, 31, 61, 3, 59, 29, 57, 14, 11, 27, 53, 13, 51, 1, 49, 12, 47, 23, 9, 11, 43, 21, 41, 2, 39, 19, 37, 9, 7, 17, 33, 8, 31, 3, 29, 7, 27, 13, 1, 6, 23, 11, 21, 1, 19, 9, 17, 4, 3, 7, 13, 3, 11, 1, 9, 2, 7, 3, 1, 1, 3, 1, 1, 0};
qbyte p2multitable[] = {0, 1, 1, 3, 2, 1, 3, 7, 2, 9, 1, 11, 3, 13, 7, 3, 4, 17, 9, 19, 1, 21, 11, 23, 6, 1, 13, 27, 7, 29, 3, 31, 8, 33, 17, 7, 9, 37, 19, 39, 2, 41, 21, 43, 11, 9, 23, 47, 12, 49, 1, 51, 13, 53, 27, 11, 14, 57, 29, 59, 3, 61, 31, 63, 16, 13, 33, 67, 17, 69, 7, 71, 18, 73, 37, 3, 19, 77, 39, 79, 4, 81, 41, 83, 21, 17, 43, 87, 22, 89, 9, 91, 23, 93, 47, 19, 24, 97, 49, 99, 1};
tlookup *t_lookup;
tlookupp *t_curlookupp;
int t_curtable;
int t_numtables;
int t_numtablesinv;//numtables/65546
#define palette host_basepal
#define _abs(x) ((x)*(x))
void R_CalcTransTable(int table, int level)
{
FILE * f;
int p;
int p2;
int r, g, b, j;
int i;
unsigned char *pa;
int m;
int dif, curdif;
qbyte p1multi;
qbyte p2multi;
qbyte pixdivide;
p1multi = p1multitable[level];
p2multi = p2multitable[level];
pixdivide = p1multi + p2multi;
COM_FOpenFile (va("data/ttable%i.dat", (int) level) , &f); //we can ignore the filesize return value
if (f)
{
if (fread (t_lookup[table], 256, 256, f) == 256)
{
fclose(f);
return;
}
fclose(f);
}
Con_Printf("Generating transtable %i%%\n", level);
for (p = 0; p < 256; p++)
{
j = p*3;
for (p2 = 0; p2 < 256; p2++)
{
dif = 0x7fffffff;
m=0;
i = p2*3;
r = (palette[j+0] * p1multi + palette[i+0] * p2multi) / pixdivide;
g = (palette[j+1] * p1multi + palette[i+1] * p2multi) / pixdivide;
b = (palette[j+2] * p1multi + palette[i+2] * p2multi) / pixdivide;
for (i = 0,pa=palette; i < 256-16; i++,pa+=3)
{
curdif = _abs(r - pa[0]) + _abs(g - pa[1]) + _abs(b - pa[2]);
if (curdif <= 0) //force 0
{
m = i;
break;
}
if (curdif < dif)
{
dif = curdif;
m = i;
}
}
(t_lookup[table])[p][p2] = m;
}
}
COM_CreatePath(va("%s/data/", com_gamedir));
#if 1
f = fopen (va("%s/data/ttable%i.dat", com_gamedir, (int) level), "wb");
if (f)
{
if (fwrite (t_lookup[table], 256, 256, f) != 256)
{
Con_Printf("Couldn't write data to \"data/ttable%i.dat\"\n", (int) level);
fclose(f);
return;
}
fclose(f);
}
else
Con_Printf("Couldn't write data to \"data/ttable%i.dat\"\n", (int) level);
#else
COM_WriteFile(va("data/ttable%i.dat", (int)level, t_lookup[table], 256*256);
#endif
}
void D_InitTrans(void)
{
int i;
int table;
if (t_lookup)
BZ_Free(t_lookup);
//no trans palette yet..
Con_SafePrintf("Making/loading transparency lookup tables\nPlease wait...\n");
MakeVideoPalette();
if ((i = COM_CheckParm("-ttables")) != 0)
{
t_numtables = Q_atoi(com_argv[i+1]);
if (t_numtables < 1)
t_numtables = 1;
}
else
t_numtables = 5;
t_numtablesinv = ((float)65536/t_numtables)+1;//65546/numtables
t_curtable=0;
//t_lookup = Hunk_AllocName(sizeof(tlookup)*t_numtables, "Transtables");
t_lookup = BZ_Malloc(sizeof(tlookup)*t_numtables);
t_curlookupp = t_lookup[t_curtable];
if (t_numtables == 1)
R_CalcTransTable(0, 50);
else if (t_numtables == 2)
{
R_CalcTransTable(0, 50);
R_CalcTransTable(1, 100);
}
else
{
for (table = 0; table < t_numtables; table++)
R_CalcTransTable(table, 100/((float)(t_numtables-1)/table));
}
Con_Printf("Done\n");
}
#ifndef Trans
byte _fastcall Trans(byte p, byte p2)
{
return t_curlookupp[p][p2];
}
#endif
void Set_TransLevelI(int level)
{
/*
0 =0
12.5 =1
25 =2
37.5 =3
50 =4
62.5 =5
75 =6
87.5 =7
100 =8
*/
t_curtable = level/(100.0f/(t_numtables-1));
t_curlookupp = t_lookup[t_curtable];
}
void Set_TransLevelF(float level) //MUST be between 0 and 1
{
// level+=1.0/(NUMTABLES-1);
if (level>1)
level = 1;
t_curtable = level*(t_numtables-1);
t_curlookupp = t_lookup[t_curtable];
}
#endif

51
engine/sw/d_vars.c Normal file
View file

@ -0,0 +1,51 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_vars.c: global refresh variables
#if !id386
#include "quakedef.h"
// all global and static refresh variables are collected in a contiguous block
// to avoid cache conflicts.
//-------------------------------------------------------
// global refresh variables
//-------------------------------------------------------
// FIXME: make into one big structure, like cl or sv
// FIXME: do separately for refresh engine and driver
float d_sdivzstepu, d_tdivzstepu, d_zistepu;
float d_sdivzstepv, d_tdivzstepv, d_zistepv;
float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
fixed16_t sadjust, tadjust, bbextents, bbextentt;
pixel_t *cacheblock;
int cachewidth;
int cacheheight;
pixel_t *d_viewbuffer;
short *d_pzbuffer;
unsigned int d_zrowbytes;
unsigned int d_zwidth;
#endif // !id386

213
engine/sw/d_varsa.s Normal file
View file

@ -0,0 +1,213 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// d_varsa.s
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"
#if id386
.data
//-------------------------------------------------------
// global refresh variables
//-------------------------------------------------------
// FIXME: put all refresh variables into one contiguous block. Make into one
// big structure, like cl or sv?
.align 4
.globl C(d_sdivzstepu)
.globl C(d_tdivzstepu)
.globl C(d_zistepu)
.globl C(d_sdivzstepv)
.globl C(d_tdivzstepv)
.globl C(d_zistepv)
.globl C(d_sdivzorigin)
.globl C(d_tdivzorigin)
.globl C(d_ziorigin)
C(d_sdivzstepu): .single 0
C(d_tdivzstepu): .single 0
C(d_zistepu): .single 0
C(d_sdivzstepv): .single 0
C(d_tdivzstepv): .single 0
C(d_zistepv): .single 0
C(d_sdivzorigin): .single 0
C(d_tdivzorigin): .single 0
C(d_ziorigin): .single 0
.globl C(sadjust)
.globl C(tadjust)
.globl C(bbextents)
.globl C(bbextentt)
C(sadjust): .long 0
C(tadjust): .long 0
C(bbextents): .long 0
C(bbextentt): .long 0
.globl C(cacheblock)
.globl C(d_viewbuffer)
.globl C(cachewidth)
.globl C(d_pzbuffer)
.globl C(d_zrowbytes)
.globl C(d_zwidth)
C(cacheblock): .long 0
C(cachewidth): .long 0
C(d_viewbuffer): .long 0
C(d_pzbuffer): .long 0
C(d_zrowbytes): .long 0
C(d_zwidth): .long 0
//-------------------------------------------------------
// ASM-only variables
//-------------------------------------------------------
.globl izi
izi: .long 0
.globl pbase, s, t, sfracf, tfracf, snext, tnext
.globl spancountminus1, zi16stepu, sdivz16stepu, tdivz16stepu
.globl zi8stepu, sdivz8stepu, tdivz8stepu, pz
s: .long 0
t: .long 0
snext: .long 0
tnext: .long 0
sfracf: .long 0
tfracf: .long 0
pbase: .long 0
zi8stepu: .long 0
sdivz8stepu: .long 0
tdivz8stepu: .long 0
zi16stepu: .long 0
sdivz16stepu: .long 0
tdivz16stepu: .long 0
spancountminus1: .long 0
pz: .long 0
.globl izistep
izistep: .long 0
//-------------------------------------------------------
// local variables for d_draw16.s
//-------------------------------------------------------
.globl reciprocal_table_16, entryvec_table_16
// 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13,
// 1/14, and 1/15 in 0.32 form
reciprocal_table_16: .long 0x40000000, 0x2aaaaaaa, 0x20000000
.long 0x19999999, 0x15555555, 0x12492492
.long 0x10000000, 0xe38e38e, 0xccccccc, 0xba2e8ba
.long 0xaaaaaaa, 0x9d89d89, 0x9249249, 0x8888888
#ifndef NeXT
.extern Entry2_16
.extern Entry3_16
.extern Entry4_16
.extern Entry5_16
.extern Entry6_16
.extern Entry7_16
.extern Entry8_16
.extern Entry9_16
.extern Entry10_16
.extern Entry11_16
.extern Entry12_16
.extern Entry13_16
.extern Entry14_16
.extern Entry15_16
.extern Entry16_16
#endif
entryvec_table_16: .long 0, Entry2_16, Entry3_16, Entry4_16
.long Entry5_16, Entry6_16, Entry7_16, Entry8_16
.long Entry9_16, Entry10_16, Entry11_16, Entry12_16
.long Entry13_16, Entry14_16, Entry15_16, Entry16_16
//-------------------------------------------------------
// local variables for d_parta.s
//-------------------------------------------------------
.globl DP_Count, DP_u, DP_v, DP_32768, DP_Color, DP_Pix, DP_EntryTable
DP_Count: .long 0
DP_u: .long 0
DP_v: .long 0
DP_32768: .single 32768.0
DP_Color: .long 0
DP_Pix: .long 0
#ifndef NeXT
.extern DP_1x1
.extern DP_2x2
.extern DP_3x3
.extern DP_4x4
#endif
DP_EntryTable: .long DP_1x1, DP_2x2, DP_3x3, DP_4x4
//
// advancetable is 8 bytes, but points to the middle of that range so negative
// offsets will work
//
.globl advancetable, sstep, tstep, pspantemp, counttemp, jumptemp
advancetable: .long 0, 0
sstep: .long 0
tstep: .long 0
pspantemp: .long 0
counttemp: .long 0
jumptemp: .long 0
// 1/2, 1/3, 1/4, 1/5, 1/6, and 1/7 in 0.32 form
.globl reciprocal_table, entryvec_table
reciprocal_table: .long 0x40000000, 0x2aaaaaaa, 0x20000000
.long 0x19999999, 0x15555555, 0x12492492
#ifndef NeXT
.extern Entry2_8
.extern Entry3_8
.extern Entry4_8
.extern Entry5_8
.extern Entry6_8
.extern Entry7_8
.extern Entry8_8
#endif
entryvec_table: .long 0, Entry2_8, Entry3_8, Entry4_8
.long Entry5_8, Entry6_8, Entry7_8, Entry8_8
#ifndef NeXT
.extern Spr8Entry2_8
.extern Spr8Entry3_8
.extern Spr8Entry4_8
.extern Spr8Entry5_8
.extern Spr8Entry6_8
.extern Spr8Entry7_8
.extern Spr8Entry8_8
#endif
.globl spr8entryvec_table
spr8entryvec_table: .long 0, Spr8Entry2_8, Spr8Entry3_8, Spr8Entry4_8
.long Spr8Entry5_8, Spr8Entry6_8, Spr8Entry7_8, Spr8Entry8_8
#endif // id386

53
engine/sw/d_zpoint.c Normal file
View file

@ -0,0 +1,53 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// d_zpoint.c: software driver module for drawing z-buffered points
#include "quakedef.h"
#include "d_local.h"
/*
=====================
D_DrawZPoint
=====================
*/
void D_DrawZPoint (void)
{
qbyte *pdest;
short *pz;
int izi;
pz = d_pzbuffer + (d_zwidth * r_zpointdesc.v) + r_zpointdesc.u;
pdest = d_viewbuffer + d_scantable[r_zpointdesc.v] + r_zpointdesc.u;
izi = (int)(r_zpointdesc.zi * 0x8000);
if (*pz <= izi)
{
*pz = izi;
*pdest = r_zpointdesc.color;
}
}
void D_ClearDepth(void)
{
memset(d_pzbuffer, 0, sizeof(*d_pzbuffer)*vid.width*vid.height);
}

62
engine/sw/nonintel.c Normal file
View file

@ -0,0 +1,62 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// nonintel.c: code for non-Intel processors only
//
#include "quakedef.h"
#if !id386
/*
================
R_Surf8Patch
================
*/
void R_Surf8Patch ()
{
// we only patch code on Intel
}
/*
================
R_Surf16Patch
================
*/
void R_Surf16Patch ()
{
// we only patch code on Intel
}
/*
================
R_SurfacePatch
================
*/
void R_SurfacePatch (void)
{
// we only patch code on Intel
}
#endif // !id386

358
engine/sw/r_aclip.c Normal file
View file

@ -0,0 +1,358 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_aclip.c: clip routines for drawing Alias models directly to the screen
#include "quakedef.h"
#include "r_local.h"
#include "d_local.h"
static finalvert_t fv[2][8];
static mstvert_t fstv[2][8];
static auxvert_t av[8];
void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av);
void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
finalvert_t *out);
void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
finalvert_t *out);
void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
finalvert_t *out);
void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
finalvert_t *out);
/*
================
R_Alias_clip_z
pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
================
*/
void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
{
float scale;
auxvert_t *pav0, *pav1, avout;
pav0 = &av[pfv0 - &fv[0][0]];
pav1 = &av[pfv1 - &fv[0][0]];
if (pfv0->v[1] >= pfv1->v[1])
{
scale = (ALIAS_Z_CLIP_PLANE - pav0->fv[2]) /
(pav1->fv[2] - pav0->fv[2]);
avout.fv[0] = pav0->fv[0] + (pav1->fv[0] - pav0->fv[0]) * scale;
avout.fv[1] = pav0->fv[1] + (pav1->fv[1] - pav0->fv[1]) * scale;
avout.fv[2] = ALIAS_Z_CLIP_PLANE;
out->v[2] = pfv0->v[2] + (pfv1->v[2] - pfv0->v[2]) * scale;
out->v[3] = pfv0->v[3] + (pfv1->v[3] - pfv0->v[3]) * scale;
out->v[4] = pfv0->v[4] + (pfv1->v[4] - pfv0->v[4]) * scale;
}
else
{
scale = (ALIAS_Z_CLIP_PLANE - pav1->fv[2]) /
(pav0->fv[2] - pav1->fv[2]);
avout.fv[0] = pav1->fv[0] + (pav0->fv[0] - pav1->fv[0]) * scale;
avout.fv[1] = pav1->fv[1] + (pav0->fv[1] - pav1->fv[1]) * scale;
avout.fv[2] = ALIAS_Z_CLIP_PLANE;
out->v[2] = pfv1->v[2] + (pfv0->v[2] - pfv1->v[2]) * scale;
out->v[3] = pfv1->v[3] + (pfv0->v[3] - pfv1->v[3]) * scale;
out->v[4] = pfv1->v[4] + (pfv0->v[4] - pfv1->v[4]) * scale;
}
R_AliasProjectFinalVert (out, &avout);
if (out->v[0] < r_refdef.aliasvrect.x)
out->flags |= ALIAS_LEFT_CLIP;
if (out->v[1] < r_refdef.aliasvrect.y)
out->flags |= ALIAS_TOP_CLIP;
if (out->v[0] > r_refdef.aliasvrectright)
out->flags |= ALIAS_RIGHT_CLIP;
if (out->v[1] > r_refdef.aliasvrectbottom)
out->flags |= ALIAS_BOTTOM_CLIP;
}
#if !id386
void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
{
float scale;
int i;
if (pfv0->v[1] >= pfv1->v[1])
{
scale = (float)(r_refdef.aliasvrect.x - pfv0->v[0]) /
(pfv1->v[0] - pfv0->v[0]);
for (i=0 ; i<6 ; i++)
out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5;
}
else
{
scale = (float)(r_refdef.aliasvrect.x - pfv1->v[0]) /
(pfv0->v[0] - pfv1->v[0]);
for (i=0 ; i<6 ; i++)
out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5;
}
}
void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
finalvert_t *out)
{
float scale;
int i;
if (pfv0->v[1] >= pfv1->v[1])
{
scale = (float)(r_refdef.aliasvrectright - pfv0->v[0]) /
(pfv1->v[0] - pfv0->v[0]);
for (i=0 ; i<6 ; i++)
out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5;
}
else
{
scale = (float)(r_refdef.aliasvrectright - pfv1->v[0]) /
(pfv0->v[0] - pfv1->v[0]);
for (i=0 ; i<6 ; i++)
out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5;
}
}
void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
{
float scale;
int i;
if (pfv0->v[1] >= pfv1->v[1])
{
scale = (float)(r_refdef.aliasvrect.y - pfv0->v[1]) /
(pfv1->v[1] - pfv0->v[1]);
for (i=0 ; i<6 ; i++)
out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5;
}
else
{
scale = (float)(r_refdef.aliasvrect.y - pfv1->v[1]) /
(pfv0->v[1] - pfv1->v[1]);
for (i=0 ; i<6 ; i++)
out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5;
}
}
void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
finalvert_t *out)
{
float scale;
int i;
if (pfv0->v[1] >= pfv1->v[1])
{
scale = (float)(r_refdef.aliasvrectbottom - pfv0->v[1]) /
(pfv1->v[1] - pfv0->v[1]);
for (i=0 ; i<6 ; i++)
out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5;
}
else
{
scale = (float)(r_refdef.aliasvrectbottom - pfv1->v[1]) /
(pfv0->v[1] - pfv1->v[1]);
for (i=0 ; i<6 ; i++)
out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5;
}
}
#endif
int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
{
int i,j,k;
int flags, oldflags;
j = count-1;
k = 0;
for (i=0 ; i<count ; j = i, i++)
{
oldflags = in[j].flags & flag;
flags = in[i].flags & flag;
if (flags && oldflags)
continue;
if (oldflags ^ flags)
{
clip (&in[j], &in[i], &out[k]);
out[k].flags = 0;
if (out[k].v[0] < r_refdef.aliasvrect.x)
out[k].flags |= ALIAS_LEFT_CLIP;
if (out[k].v[1] < r_refdef.aliasvrect.y)
out[k].flags |= ALIAS_TOP_CLIP;
if (out[k].v[0] > r_refdef.aliasvrectright)
out[k].flags |= ALIAS_RIGHT_CLIP;
if (out[k].v[1] > r_refdef.aliasvrectbottom)
out[k].flags |= ALIAS_BOTTOM_CLIP;
k++;
}
if (!flags)
{
out[k] = in[i];
k++;
}
}
return k;
}
/*
================
R_AliasClipTriangle
================
*/
void R_AliasClipTriangle (mtriangle_t *ptri)
{
int i, k, pingpong;
mtriangle_t mtri;
unsigned clipflags;
mstvert_t *pst = r_affinetridesc.pstverts;
// copy vertexes and fix seam texture coordinates
fv[0][0] = pfinalverts[ptri->xyz_index[0]];
fv[0][1] = pfinalverts[ptri->xyz_index[1]];
fv[0][2] = pfinalverts[ptri->xyz_index[2]];
fv[0][0].v[2] = pst[ptri->st_index[0]].s;
fv[0][0].v[3] = pst[ptri->st_index[0]].t;
fv[0][1].v[2] = pst[ptri->st_index[1]].s;
fv[0][1].v[3] = pst[ptri->st_index[1]].t;
fv[0][2].v[2] = pst[ptri->st_index[2]].s;
fv[0][2].v[3] = pst[ptri->st_index[2]].t;
// clip
clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
if (clipflags & ALIAS_Z_CLIP)
{
for (i=0 ; i<3 ; i++)
av[i] = pauxverts[ptri->xyz_index[i]];
k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
if (k == 0)
return;
pingpong = 1;
clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
}
else
{
pingpong = 0;
k = 3;
}
if (clipflags & ALIAS_LEFT_CLIP)
{
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
if (k == 0)
return;
pingpong ^= 1;
}
if (clipflags & ALIAS_RIGHT_CLIP)
{
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
if (k == 0)
return;
pingpong ^= 1;
}
if (clipflags & ALIAS_BOTTOM_CLIP)
{
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
if (k == 0)
return;
pingpong ^= 1;
}
if (clipflags & ALIAS_TOP_CLIP)
{
k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
ALIAS_TOP_CLIP, k, R_Alias_clip_top);
if (k == 0)
return;
pingpong ^= 1;
}
for (i=0 ; i<k ; i++)
{
if (fv[pingpong][i].v[0] < r_refdef.aliasvrect.x)
fv[pingpong][i].v[0] = r_refdef.aliasvrect.x;
else if (fv[pingpong][i].v[0] > r_refdef.aliasvrectright)
fv[pingpong][i].v[0] = r_refdef.aliasvrectright;
if (fv[pingpong][i].v[1] < r_refdef.aliasvrect.y)
fv[pingpong][i].v[1] = r_refdef.aliasvrect.y;
else if (fv[pingpong][i].v[1] > r_refdef.aliasvrectbottom)
fv[pingpong][i].v[1] = r_refdef.aliasvrectbottom;
fv[pingpong][i].flags = 0;
}
// draw triangles
r_affinetridesc.ptriangles = &mtri;
r_affinetridesc.pfinalverts = fv[pingpong];
r_affinetridesc.pstverts = fstv[pingpong];
// FIXME: do all at once as trifan?
mtri.xyz_index[0] = 0;
mtri.st_index[0] = 0;
for (i=1 ; i<k-1 ; i++)
{
mtri.xyz_index[1] = i;
mtri.st_index[1] = i;
mtri.xyz_index[2] = i+1;
mtri.st_index[2] = i+1;
if (r_pixbytes == 4)
D_PolysetDraw32 ();
else
D_PolysetDraw ();
}
r_affinetridesc.pstverts = pst;
}

216
engine/sw/r_aclipa.s Normal file
View file

@ -0,0 +1,216 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// r_aliasa.s
// x86 assembly-language Alias model transform and project code.
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"
#if id386
.data
Ltemp0: .long 0
Ltemp1: .long 0
.text
#define pfv0 8+4
#define pfv1 8+8
#define out 8+12
.globl C(R_Alias_clip_bottom)
C(R_Alias_clip_bottom):
pushl %esi
pushl %edi
movl pfv0(%esp),%esi
movl pfv1(%esp),%edi
movl C(r_refdef)+rd_aliasvrectbottom,%eax
LDoForwardOrBackward:
movl fv_v+4(%esi),%edx
movl fv_v+4(%edi),%ecx
cmpl %ecx,%edx
jl LDoForward
movl fv_v+4(%esi),%ecx
movl fv_v+4(%edi),%edx
movl pfv0(%esp),%edi
movl pfv1(%esp),%esi
LDoForward:
subl %edx,%ecx
subl %edx,%eax
movl %ecx,Ltemp1
movl %eax,Ltemp0
fildl Ltemp1
fildl Ltemp0
movl out(%esp),%edx
movl $2,%eax
fdivp %st(0),%st(1) // scale
LDo3Forward:
fildl fv_v+0(%esi) // fv0v0 | scale
fildl fv_v+0(%edi) // fv1v0 | fv0v0 | scale
fildl fv_v+4(%esi) // fv0v1 | fv1v0 | fv0v0 | scale
fildl fv_v+4(%edi) // fv1v1 | fv0v1 | fv1v0 | fv0v0 | scale
fildl fv_v+8(%esi) // fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv0v0 | scale
fildl fv_v+8(%edi) // fv1v2 | fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv0v0 |
// scale
fxch %st(5) // fv0v0 | fv0v2 | fv1v1 | fv0v1 | fv1v0 | fv1v2 |
// scale
fsubr %st(0),%st(4) // fv0v0 | fv0v2 | fv1v1 | fv0v1 | fv1v0-fv0v0 |
// fv1v2 | scale
fxch %st(3) // fv0v1 | fv0v2 | fv1v1 | fv0v0 | fv1v0-fv0v0 |
// fv1v2 | scale
fsubr %st(0),%st(2) // fv0v1 | fv0v2 | fv1v1-fv0v1 | fv0v0 |
// fv1v0-fv0v0 | fv1v2 | scale
fxch %st(1) // fv0v2 | fv0v1 | fv1v1-fv0v1 | fv0v0 |
// fv1v0-fv0v0 | fv1v2 | scale
fsubr %st(0),%st(5) // fv0v2 | fv0v1 | fv1v1-fv0v1 | fv0v0 |
// fv1v0-fv0v0 | fv1v2-fv0v2 | scale
fxch %st(6) // scale | fv0v1 | fv1v1-fv0v1 | fv0v0 |
// fv1v0-fv0v0 | fv1v2-fv0v2 | fv0v2
fmul %st(0),%st(4) // scale | fv0v1 | fv1v1-fv0v1 | fv0v0 |
// (fv1v0-fv0v0)*scale | fv1v2-fv0v2 | fv0v2
addl $12,%edi
fmul %st(0),%st(2) // scale | fv0v1 | (fv1v1-fv0v1)*scale | fv0v0 |
// (fv1v0-fv0v0)*scale | fv1v2-fv0v2 | fv0v2
addl $12,%esi
addl $12,%edx
fmul %st(0),%st(5) // scale | fv0v1 | (fv1v1-fv0v1)*scale | fv0v0 |
// (fv1v0-fv0v0)*scale | (fv1v2-fv0v2)*scale |
// fv0v2
fxch %st(3) // fv0v0 | fv0v1 | (fv1v1-fv0v1)*scale | scale |
// (fv1v0-fv0v0)*scale | (fv1v2-fv0v2)*scale |
// fv0v2
faddp %st(0),%st(4) // fv0v1 | (fv1v1-fv0v1)*scale | scale |
// fv0v0+(fv1v0-fv0v0)*scale |
// (fv1v2-fv0v2)*scale | fv0v2
faddp %st(0),%st(1) // fv0v1+(fv1v1-fv0v1)*scale | scale |
// fv0v0+(fv1v0-fv0v0)*scale |
// (fv1v2-fv0v2)*scale | fv0v2
fxch %st(4) // fv0v2 | scale | fv0v0+(fv1v0-fv0v0)*scale |
// (fv1v2-fv0v2)*scale | fv0v1+(fv1v1-fv0v1)*scale
faddp %st(0),%st(3) // scale | fv0v0+(fv1v0-fv0v0)*scale |
// fv0v2+(fv1v2-fv0v2)*scale |
// fv0v1+(fv1v1-fv0v1)*scale
fxch %st(1) // fv0v0+(fv1v0-fv0v0)*scale | scale |
// fv0v2+(fv1v2-fv0v2)*scale |
// fv0v1+(fv1v1-fv0v1)*scale
fadds float_point5
fxch %st(3) // fv0v1+(fv1v1-fv0v1)*scale | scale |
// fv0v2+(fv1v2-fv0v2)*scale |
// fv0v0+(fv1v0-fv0v0)*scale
fadds float_point5
fxch %st(2) // fv0v2+(fv1v2-fv0v2)*scale | scale |
// fv0v1+(fv1v1-fv0v1)*scale |
// fv0v0+(fv1v0-fv0v0)*scale
fadds float_point5
fxch %st(3) // fv0v0+(fv1v0-fv0v0)*scale | scale |
// fv0v1+(fv1v1-fv0v1)*scale |
// fv0v2+(fv1v2-fv0v2)*scale
fistpl fv_v+0-12(%edx) // scale | fv0v1+(fv1v1-fv0v1)*scale |
// fv0v2+(fv1v2-fv0v2)*scale
fxch %st(1) // fv0v1+(fv1v1-fv0v1)*scale | scale |
// fv0v2+(fv1v2-fv0v2)*scale | scale
fistpl fv_v+4-12(%edx) // scale | fv0v2+(fv1v2-fv0v2)*scale
fxch %st(1) // fv0v2+(fv1v2-fv0v2)*sc | scale
fistpl fv_v+8-12(%edx) // scale
decl %eax
jnz LDo3Forward
fstp %st(0)
popl %edi
popl %esi
ret
.globl C(R_Alias_clip_top)
C(R_Alias_clip_top):
pushl %esi
pushl %edi
movl pfv0(%esp),%esi
movl pfv1(%esp),%edi
movl C(r_refdef)+rd_aliasvrect+4,%eax
jmp LDoForwardOrBackward
.globl C(R_Alias_clip_right)
C(R_Alias_clip_right):
pushl %esi
pushl %edi
movl pfv0(%esp),%esi
movl pfv1(%esp),%edi
movl C(r_refdef)+rd_aliasvrectright,%eax
LRightLeftEntry:
movl fv_v+4(%esi),%edx
movl fv_v+4(%edi),%ecx
cmpl %ecx,%edx
movl fv_v+0(%esi),%edx
movl fv_v+0(%edi),%ecx
jl LDoForward2
movl fv_v+0(%esi),%ecx
movl fv_v+0(%edi),%edx
movl pfv0(%esp),%edi
movl pfv1(%esp),%esi
LDoForward2:
jmp LDoForward
.globl C(R_Alias_clip_left)
C(R_Alias_clip_left):
pushl %esi
pushl %edi
movl pfv0(%esp),%esi
movl pfv1(%esp),%edi
movl C(r_refdef)+rd_aliasvrect+0,%eax
jmp LRightLeftEntry
#endif // id386

935
engine/sw/r_alias.c Normal file
View file

@ -0,0 +1,935 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_alias.c: routines for setting up to draw alias models
//changes include stvertexes now being seperatly number from the triangles.
//this allows q2 models to be supported.
//lerping is also available.
//future aims include better skin management.
//the asm code cannot handle alias models anymore.
#ifndef NOASM
#define NOASM
#endif
#include "quakedef.h"
#include "r_local.h"
#include "d_local.h" // FIXME: shouldn't be needed (is needed for patch
// right now, but that should move)
#define Q2RF_DEPTHHACK 16 // for view weapon Z crunching
#define LIGHT_MIN 5 // lowest light value we'll allow, to avoid the
// need for inner-loop light clamping
mtriangle_t *ptriangles;
affinetridesc_t r_affinetridesc;
void * acolormap; // FIXME: should go away
dtrivertx_t *r_apoldverts;
dtrivertx_t *r_apnewverts;
vec3_t r_afrntlerp;
vec3_t r_abacklerp;
vec3_t r_amovelerp;
// TODO: these probably will go away with optimized rasterization
mmdl_t *pmdl;
vec3_t r_plightvec;
int r_ambientlight;
float r_shadelight;
aliashdr_t *paliashdr;
finalvert_t *pfinalverts;
auxvert_t *pauxverts;
static float ziscale;
static model_t *pmodel;
extern int cl_playerindex;
static vec3_t alias_forward, alias_right, alias_up;
static maliasskindesc_t *pskindesc;
int r_amodels_drawn;
int a_skinwidth;
int r_anumverts;
float aliastransform[3][4];
typedef struct {
int index0;
int index1;
} aedge_t;
static aedge_t aedges[12] = {
{0, 1}, {1, 2}, {2, 3}, {3, 0},
{4, 5}, {5, 6}, {6, 7}, {7, 4},
{0, 5}, {1, 4}, {2, 7}, {3, 6}
};
#define NUMVERTEXNORMALS 162
extern float r_avertexnormals[NUMVERTEXNORMALS][3];
void R_AliasTransformAndProjectFinalVerts (finalvert_t *fv);//,
//mstvert_t *pstverts);
void R_AliasSetUpTransform (int trivial_accept);
void R_AliasTransformVector (vec3_t in, vec3_t out);
void R_AliasTransformFinalVert (finalvert_t *fv, auxvert_t *av,
dtrivertx_t *pnewverts, dtrivertx_t *poldverts);//, mstvert_t *pstverts);
void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av);
/*
================
R_AliasCheckBBox
================
*/
qboolean R_AliasCheckBBox (void)
{
int i, flags, nframe, oframe, numv;
aliashdr_t *pahdr;
float zi, basepts[8][3], v0, v1, frac;
finalvert_t *pv0, *pv1, viewpts[16];
auxvert_t *pa0, *pa1, viewaux[16];
maliasframedesc_t *pnewframedesc, *poldframedesc;
qboolean zclipped, zfullyclipped;
unsigned anyclip, allclip;
int minz;
float a, b;
vec3_t min, max;
// expand, rotate, and translate points into worldspace
currententity->trivial_accept = 0;
pmodel = currententity->model;
pahdr = SWMod_Extradata (pmodel);
pmdl = (mmdl_t *)((qbyte *)pahdr + pahdr->model);
R_AliasSetUpTransform (0);
// construct the base bounding box for this frame
nframe = currententity->frame;
// TODO: don't repeat this check when drawing?
if ((nframe >= pmdl->numframes) || (nframe < 0))
{
Con_DPrintf ("No such frame %d %s\n", nframe,
pmodel->name);
nframe = 0;
}
// construct the base bounding box for this frame
oframe = currententity->frame;
// TODO: don't repeat this check when drawing?
if ((oframe >= pmdl->numframes) || (oframe < 0))
{
Con_DPrintf ("No such frame %d %s\n", oframe,
pmodel->name);
oframe = 0;
}
pnewframedesc = &pahdr->frames[nframe];
poldframedesc = &pahdr->frames[oframe];
for (i = 0; i < 3; i++) //choose the most outward of the two.
{
a = poldframedesc->scale_origin[i] + poldframedesc->bboxmin.v[i]*poldframedesc->scale[i];
b = pnewframedesc->scale_origin[i] + pnewframedesc->bboxmin.v[i]*pnewframedesc->scale[i];
min[i] = a>b?b:a;
a = poldframedesc->scale_origin[i] + poldframedesc->bboxmax.v[i]*poldframedesc->scale[i];
b = pnewframedesc->scale_origin[i] + pnewframedesc->bboxmax.v[i]*pnewframedesc->scale[i];
max[i] = a>b?a:b;
}
// x worldspace coordinates
basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] = min[0];
basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] = max[0];
// y worldspace coordinates
basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] = min[1];
basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] = max[1];
// z worldspace coordinates
basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] = min[2];
basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] = max[2];
zclipped = false;
zfullyclipped = true;
minz = 9999;
for (i=0; i<8 ; i++)
{
R_AliasTransformVector (&basepts[i][0], &viewaux[i].fv[0]);
if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE)
{
// we must clip points that are closer than the near clip plane
viewpts[i].flags = ALIAS_Z_CLIP;
zclipped = true;
}
else
{
if (viewaux[i].fv[2] < minz)
minz = viewaux[i].fv[2];
viewpts[i].flags = 0;
zfullyclipped = false;
}
}
if (zfullyclipped)
{
return false; // everything was near-z-clipped
}
numv = 8;
if (zclipped)
{
// organize points by edges, use edges to get new points (possible trivial
// reject)
for (i=0 ; i<12 ; i++)
{
// edge endpoints
pv0 = &viewpts[aedges[i].index0];
pv1 = &viewpts[aedges[i].index1];
pa0 = &viewaux[aedges[i].index0];
pa1 = &viewaux[aedges[i].index1];
// if one end is clipped and the other isn't, make a new point
if (pv0->flags ^ pv1->flags)
{
frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) /
(pa1->fv[2] - pa0->fv[2]);
viewaux[numv].fv[0] = pa0->fv[0] +
(pa1->fv[0] - pa0->fv[0]) * frac;
viewaux[numv].fv[1] = pa0->fv[1] +
(pa1->fv[1] - pa0->fv[1]) * frac;
viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE;
viewpts[numv].flags = 0;
numv++;
}
}
}
// project the vertices that remain after clipping
anyclip = 0;
allclip = ALIAS_XY_CLIP_MASK;
// TODO: probably should do this loop in ASM, especially if we use floats
for (i=0 ; i<numv ; i++)
{
// we don't need to bother with vertices that were z-clipped
if (viewpts[i].flags & ALIAS_Z_CLIP)
continue;
zi = 1.0 / viewaux[i].fv[2];
// FIXME: do with chop mode in ASM, or convert to float
v0 = (viewaux[i].fv[0] * xscale * zi) + xcenter;
v1 = (viewaux[i].fv[1] * yscale * zi) + ycenter;
flags = 0;
if (v0 < r_refdef.fvrectx)
flags |= ALIAS_LEFT_CLIP;
if (v1 < r_refdef.fvrecty)
flags |= ALIAS_TOP_CLIP;
if (v0 > r_refdef.fvrectright)
flags |= ALIAS_RIGHT_CLIP;
if (v1 > r_refdef.fvrectbottom)
flags |= ALIAS_BOTTOM_CLIP;
anyclip |= flags;
allclip &= flags;
}
if (allclip)
return false; // trivial reject off one side
// currententity->trivial_accept = !anyclip & !zclipped;
if (currententity->trivial_accept)
{
if (minz > (r_aliastransition + (pmdl->size * r_resfudge)))
{
// currententity->trivial_accept |= 2;
}
}
return true;
}
/*
================
R_AliasTransformVector
================
*/
void R_AliasTransformVector (vec3_t in, vec3_t out)
{
out[0] = DotProduct(in, aliastransform[0]) + aliastransform[0][3];
out[1] = DotProduct(in, aliastransform[1]) + aliastransform[1][3];
out[2] = DotProduct(in, aliastransform[2]) + aliastransform[2][3];
}
/*
================
R_AliasPreparePoints
General clipped case
================
*/
void R_AliasPreparePoints (void)
{
int i;
mstvert_t *pstverts;
finalvert_t *fv;
auxvert_t *av;
mtriangle_t *ptri;
finalvert_t *pfv[3];
r_anumverts = pmdl->numverts;
fv = pfinalverts;
av = pauxverts;
#ifdef PEXT_TRANS
if (currententity->alpha != 1)
{
Set_TransLevelF(currententity->alpha);
}
#endif
for (i=0 ; i<r_anumverts ; i++, fv++, av++, r_apnewverts++, r_apoldverts++)
{
R_AliasTransformFinalVert (fv, av, r_apnewverts, r_apoldverts);
if (av->fv[2] < ALIAS_Z_CLIP_PLANE)
fv->flags |= ALIAS_Z_CLIP;
else
{
R_AliasProjectFinalVert (fv, av);
if (fv->v[0] < r_refdef.aliasvrect.x)
fv->flags |= ALIAS_LEFT_CLIP;
if (fv->v[1] < r_refdef.aliasvrect.y)
fv->flags |= ALIAS_TOP_CLIP;
if (fv->v[0] > r_refdef.aliasvrectright)
fv->flags |= ALIAS_RIGHT_CLIP;
if (fv->v[1] > r_refdef.aliasvrectbottom)
fv->flags |= ALIAS_BOTTOM_CLIP;
}
}
pstverts = (mstvert_t *)((qbyte *)paliashdr + paliashdr->stverts);
//
// clip and draw all triangles
//
r_affinetridesc.numtriangles = 1;
ptri = (mtriangle_t *)((qbyte *)paliashdr + paliashdr->triangles);
for (i=0 ; i<pmdl->numtris ; i++, ptri++)
{
pfv[0] = &pfinalverts[ptri->xyz_index[0]];
pfv[1] = &pfinalverts[ptri->xyz_index[1]];
pfv[2] = &pfinalverts[ptri->xyz_index[2]];
if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) )
continue; // completely clipped
pfv[0]->v[2] = pstverts[ptri->st_index[0]].s;
pfv[0]->v[3] = pstverts[ptri->st_index[0]].t;
pfv[1]->v[2] = pstverts[ptri->st_index[1]].s;
pfv[1]->v[3] = pstverts[ptri->st_index[1]].t;
pfv[2]->v[2] = pstverts[ptri->st_index[2]].s;
pfv[2]->v[3] = pstverts[ptri->st_index[2]].t;
if ( ! ( (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) &
(ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) )
{ // totally unclipped
r_affinetridesc.pfinalverts = pfinalverts;
r_affinetridesc.ptriangles = ptri;
if (r_pixbytes == 4)
D_PolysetDraw32 ();
else if (r_pixbytes == 2)
D_PolysetDraw16 ();
else
D_PolysetDraw ();
}
else
{ // partially clipped
R_AliasClipTriangle (ptri);
}
}
}
/*
================
R_AliasSetUpTransform
================
*/
void R_AliasSetUpTransform (int trivial_accept)
{
int i;
float rotationmatrix[3][4], t2matrix[3][4];
static float tmatrix[3][4];
static float viewmatrix[3][4];
vec3_t angles;
// TODO: should really be stored with the entity instead of being reconstructed
// TODO: should use a look-up table
// TODO: could cache lazily, stored in the entity
angles[ROLL] = currententity->angles[ROLL];
angles[PITCH] = -currententity->angles[PITCH];
angles[YAW] = currententity->angles[YAW];
AngleVectors (angles, alias_forward, alias_right, alias_up);
tmatrix[0][0] = currententity->scale;
tmatrix[1][1] = currententity->scale;
tmatrix[2][2] = currententity->scale;
tmatrix[0][3] = 0;
tmatrix[1][3] = 0;
tmatrix[2][3] = 0;
// TODO: can do this with simple matrix rearrangement
for (i=0 ; i<3 ; i++)
{
t2matrix[i][0] = alias_forward[i];
t2matrix[i][1] = -alias_right[i];
t2matrix[i][2] = alias_up[i];
}
t2matrix[0][3] = -modelorg[0];
t2matrix[1][3] = -modelorg[1];
t2matrix[2][3] = -modelorg[2];
// FIXME: can do more efficiently than full concatenation
R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
// TODO: should be global, set when vright, etc., set
VectorCopy (vright, viewmatrix[0]);
VectorCopy (vup, viewmatrix[1]);
VectorInverse (viewmatrix[1]);
VectorCopy (vpn, viewmatrix[2]);
// viewmatrix[0][3] = 0;
// viewmatrix[1][3] = 0;
// viewmatrix[2][3] = 0;
R_ConcatTransforms (viewmatrix, rotationmatrix, aliastransform);
// do the scaling up of x and y to screen coordinates as part of the transform
// for the unclipped case (it would mess up clipping in the clipped case).
// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y
// correspondingly so the projected x and y come out right
// FIXME: make this work for clipped case too?
if (trivial_accept)
{
for (i=0 ; i<4 ; i++)
{
aliastransform[0][i] *= aliasxscale *
(1.0 / ((float)0x8000 * 0x10000));
aliastransform[1][i] *= aliasyscale *
(1.0 / ((float)0x8000 * 0x10000));
aliastransform[2][i] *= 1.0 / ((float)0x8000 * 0x10000);
}
}
}
/*
================
R_AliasTransformFinalVert
================
*/
void R_AliasTransformFinalVert (finalvert_t *fv, auxvert_t *av,
dtrivertx_t *pnewverts, dtrivertx_t *poldverts)//, mstvert_t *pstverts)
{
int temp;
float lightcos, *plightnormal;
vec3_t lerp_org;
lerp_org[0] = r_amovelerp[0] + pnewverts->v[0]*r_afrntlerp[0] + poldverts->v[0]*r_abacklerp[0];
lerp_org[1] = r_amovelerp[1] + pnewverts->v[1]*r_afrntlerp[1] + poldverts->v[1]*r_abacklerp[1];
lerp_org[2] = r_amovelerp[2] + pnewverts->v[2]*r_afrntlerp[2] + poldverts->v[2]*r_abacklerp[2];
av->fv[0] = DotProduct(lerp_org, aliastransform[0]) +
aliastransform[0][3];
av->fv[1] = DotProduct(lerp_org, aliastransform[1]) +
aliastransform[1][3];
av->fv[2] = DotProduct(lerp_org, aliastransform[2]) +
aliastransform[2][3];
fv->v[2] = 0;
fv->v[3] = 0;
fv->flags = 0;
// lighting
plightnormal = r_avertexnormals[pnewverts->lightnormalindex];
lightcos = DotProduct (plightnormal, r_plightvec);
temp = r_ambientlight;
if (lightcos < 0)
{
temp += (int)(r_shadelight * lightcos);
// clamp; because we limited the minimum ambient and shading light, we
// don't have to clamp low light, just bright
if (temp < 0)
temp = 0;
}
fv->v[4] = temp;
}
#if 1 //!id386 since stvert_t was changed.
/*
================
R_AliasTransformAndProjectFinalVerts
================
*/
void R_AliasTransformAndProjectFinalVerts (finalvert_t *fv)//, stvert_t *pstverts)
{
int i, temp;
float lightcos, *plightnormal, zi;
dtrivertx_t *pnewverts, *poldverts;
vec3_t lerp_org;
pnewverts = r_apnewverts;
poldverts = r_apoldverts;
for (i=0 ; i<r_anumverts ; i++, fv++, pnewverts++, poldverts++)
{
lerp_org[0] = r_amovelerp[0] + pnewverts->v[0]*r_afrntlerp[0] + poldverts->v[0]*r_abacklerp[0];
lerp_org[1] = r_amovelerp[1] + pnewverts->v[1]*r_afrntlerp[1] + poldverts->v[1]*r_abacklerp[1];
lerp_org[2] = r_amovelerp[2] + pnewverts->v[2]*r_afrntlerp[2] + poldverts->v[2]*r_abacklerp[2];
// transform and project
zi = 1.0 / (DotProduct(lerp_org, aliastransform[2]) +
aliastransform[2][3]);
// x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is
// scaled up by 1/2**31, and the scaling cancels out for x and y in the
// projection
fv->v[5] = zi;
fv->v[0] = ((DotProduct(lerp_org, aliastransform[0]) +
aliastransform[0][3]) * zi) + aliasxcenter;
fv->v[1] = ((DotProduct(lerp_org, aliastransform[1]) +
aliastransform[1][3]) * zi) + aliasycenter;
fv->v[2] = 0;//pstverts->s;
fv->v[3] = 0;//pstverts->t;
fv->flags = 0;
// lighting
plightnormal = r_avertexnormals[pnewverts->lightnormalindex]; //don't bother lerping light.
lightcos = DotProduct (plightnormal, r_plightvec);
temp = r_ambientlight;
if (lightcos < 0)
{
temp += (int)(r_shadelight * lightcos);
// clamp; because we limited the minimum ambient and shading light, we
// don't have to clamp low light, just bright
if (temp < 0)
temp = 0;
}
fv->v[4] = temp;
}
}
#endif
/*
================
R_AliasProjectFinalVert
================
*/
void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av)
{
float zi;
// project points
zi = 1.0 / av->fv[2];
fv->v[5] = zi * ziscale;
fv->v[0] = (av->fv[0] * aliasxscale * zi) + aliasxcenter;
fv->v[1] = (av->fv[1] * aliasyscale * zi) + aliasycenter;
}
/*
================
R_AliasPrepareUnclippedPoints
================
*/
void R_AliasPrepareUnclippedPoints (void)
{
finalvert_t *fv;
r_anumverts = pmdl->numverts;
// FIXME: just use pfinalverts directly?
fv = pfinalverts;
R_AliasTransformAndProjectFinalVerts (fv);
if (r_affinetridesc.drawtype)
{
if (r_pixbytes == 4)
D_PolysetDrawFinalVerts32Trans (fv, r_anumverts);
else
D_PolysetDrawFinalVerts (fv, r_anumverts);
}
r_affinetridesc.pfinalverts = pfinalverts;
r_affinetridesc.ptriangles = (mtriangle_t *)
((qbyte *)paliashdr + paliashdr->triangles);
r_affinetridesc.numtriangles = pmdl->numtris;
if (r_pixbytes == 4)
D_PolysetDraw32 ();
else
D_PolysetDraw ();
}
/*
===============
R_AliasSetupSkin
===============
*/
void R_AliasSetupSkin (void)
{
int skinnum;
int i, numskins;
maliasskingroup_t *paliasskingroup;
float *pskinintervals, fullskininterval;
float skintargettime, skintime;
skinnum = currententity->skinnum;
if ((skinnum >= pmdl->numskins) || (skinnum < 0))
{
Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum);
skinnum = 0;
}
pskindesc = ((maliasskindesc_t *)
((qbyte *)paliashdr + paliashdr->skindesc)) + skinnum;
a_skinwidth = pmdl->skinwidth;
if (pskindesc->type == ALIAS_SKIN_GROUP)
{
paliasskingroup = (maliasskingroup_t *)((qbyte *)paliashdr +
pskindesc->skin);
pskinintervals = (float *)
((qbyte *)paliashdr + paliasskingroup->intervals);
numskins = paliasskingroup->numskins;
fullskininterval = pskinintervals[numskins-1];
skintime = cl.time + currententity->syncbase;
// when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval
// values are positive, so we don't have to worry about division by 0
skintargettime = skintime -
((int)(skintime / fullskininterval)) * fullskininterval;
for (i=0 ; i<(numskins-1) ; i++)
{
if (pskinintervals[i] > skintargettime)
break;
}
pskindesc = &paliasskingroup->skindescs[i];
}
r_affinetridesc.pskindesc = pskindesc;
r_affinetridesc.pskin = (void *)((qbyte *)paliashdr + pskindesc->skin);
r_affinetridesc.skinwidth = a_skinwidth;
r_affinetridesc.skinheight = pmdl->skinheight;
if (currententity->model != cl.model_precache[cl_playerindex])
return;
//alternate player skins.
if (currententity->scoreboard && r_pixbytes == 1)
{
qbyte *base;
skin_t *skin;
if (!currententity->scoreboard->skin)
Skin_Find (currententity->scoreboard);
base = Skin_Cache8 (currententity->scoreboard->skin);
skin = currententity->scoreboard->skin;
if (base && skin->cachedbpp == r_pixbytes*8)
{
r_affinetridesc.pskin = base;
r_affinetridesc.skinwidth = skin->width;
r_affinetridesc.skinheight = skin->height;
}
}
else if (currententity->scoreboard)
{
qbyte *base;
skin_t *skin;
if (!currententity->scoreboard->skin)
Skin_Find (currententity->scoreboard);
base = Skin_Cache32 (currententity->scoreboard->skin);
skin = currententity->scoreboard->skin;
if (base && skin->cachedbpp == r_pixbytes*8)
{
r_affinetridesc.pskin = base;
r_affinetridesc.skinwidth = skin->width;
r_affinetridesc.skinheight = skin->height;
}
}
}
/*
================
R_AliasSetupLighting
================
*/
void R_AliasSetupLighting (alight_t *plighting)
{
if (r_pixbytes == 4)
{ //fixes inverse lighting in sw 32.
//we fix it here so the lighting code doesn't have to have lots of extra minuses, as they are multiplied out
plighting->ambientlight=(128-plighting->ambientlight);
plighting->shadelight=(128-plighting->shadelight);
}
// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
// to clamp off the bottom
r_ambientlight = plighting->ambientlight;
r_shadelight = plighting->shadelight;
if (r_ambientlight < LIGHT_MIN)
r_ambientlight = LIGHT_MIN;
r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
if (r_ambientlight < LIGHT_MIN)
r_ambientlight = LIGHT_MIN;
if (r_shadelight < 0)
r_shadelight = 0;
r_shadelight *= VID_GRADES;
// rotate the lighting vector into the model's frame of reference
r_plightvec[0] = DotProduct (plighting->plightvec, alias_forward);
r_plightvec[1] = -DotProduct (plighting->plightvec, alias_right);
r_plightvec[2] = DotProduct (plighting->plightvec, alias_up);
}
/*
=================
R_AliasSetupFrame
set r_apverts
=================
*/
void R_AliasSetupFrame (void)
{
int frame, oframe;
int i, numframes;
maliasgroup_t *paliasgroup;
float *pintervals, fullinterval, targettime, time;
// float *min1, *min2;
// vec3_t max1, max2;
float fl, bl;
frame = currententity->frame;
if ((frame >= pmdl->numframes) || (frame < 0))
{
Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
frame = 0;
}
oframe = currententity->oldframe;
if ((oframe >= pmdl->numframes) || (oframe < 0))
{
// Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", oframe); //pointless
oframe = 0;
}
bl = currententity->lerptime;
fl = 1.0 - bl;
for (i = 0; i < 3; i++)
{
r_abacklerp[i] = paliashdr->frames[oframe].scale[i]*bl;
r_afrntlerp[i] = paliashdr->frames[frame].scale[i]*fl;
r_amovelerp[i] = paliashdr->frames[frame].scale_origin[i]*fl + paliashdr->frames[oframe].scale_origin[i]*bl;
}
if (paliashdr->frames[frame].type == ALIAS_SINGLE)
{
r_apnewverts = (dtrivertx_t *)
((qbyte *)paliashdr + paliashdr->frames[frame].frame);
}
else
{
paliasgroup = (maliasgroup_t *)
((qbyte *)paliashdr + paliashdr->frames[frame].frame);
pintervals = (float *)((qbyte *)paliashdr + paliasgroup->intervals);
numframes = paliasgroup->numframes;
fullinterval = pintervals[numframes-1];
time = cl.time + currententity->syncbase;
//
// when loading in Mod_LoadAliasGroup, we guaranteed all interval values
// are positive, so we don't have to worry about division by 0
//
targettime = time - ((int)(time / fullinterval)) * fullinterval;
for (i=0 ; i<(numframes-1) ; i++)
{
if (pintervals[i] > targettime)
break;
}
r_apnewverts = (dtrivertx_t *)
((qbyte *)paliashdr + paliasgroup->frames[i].frame);
}
if (paliashdr->frames[oframe].type == ALIAS_SINGLE) //things could go haywire here...
{
r_apoldverts = (dtrivertx_t *)
((qbyte *)paliashdr + paliashdr->frames[oframe].frame);
}
else
{
paliasgroup = (maliasgroup_t *)
((qbyte *)paliashdr + paliashdr->frames[oframe].frame);
pintervals = (float *)((qbyte *)paliashdr + paliasgroup->intervals);
numframes = paliasgroup->numframes;
fullinterval = pintervals[numframes-1];
time = cl.time + currententity->syncbase;
//
// when loading in Mod_LoadAliasGroup, we guaranteed all interval values
// are positive, so we don't have to worry about division by 0
//
targettime = time - ((int)(time / fullinterval)) * fullinterval;
for (i=0 ; i<(numframes-1) ; i++)
{
if (pintervals[i] > targettime)
break;
}
r_apoldverts = (dtrivertx_t *)
((qbyte *)paliashdr + paliasgroup->frames[i].frame);
}
}
/*
================
R_AliasDrawModel
================
*/
void R_AliasDrawModel (alight_t *plighting)
{
finalvert_t finalverts[MAXALIASVERTS +
((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1];
auxvert_t auxverts[MAXALIASVERTS];
extern qbyte transfactor;
extern qbyte transbackfac;
r_amodels_drawn++;
// cache align
pfinalverts = (finalvert_t *)
(((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
pauxverts = &auxverts[0];
paliashdr = (aliashdr_t *)SWMod_Extradata (currententity->model);
pmdl = (mmdl_t *)((qbyte *)paliashdr + paliashdr->model);
R_AliasSetupSkin ();
R_AliasSetUpTransform (currententity->trivial_accept);
R_AliasSetupLighting (plighting);
R_AliasSetupFrame ();
transfactor = currententity->alpha*255;
transbackfac = 255 - transfactor;
if (!currententity->colormap)
currententity->colormap = vid.colormap;
// Sys_Error ("R_AliasDrawModel: !currententity->colormap");
r_affinetridesc.drawtype = (currententity->trivial_accept == 3) &&
r_recursiveaffinetriangles;
r_affinetridesc.pstverts = (mstvert_t *)((qbyte *)paliashdr + paliashdr->stverts);
if (r_affinetridesc.drawtype)
{
D_PolysetUpdateTables (); // FIXME: precalc...
}
else
{
#if id386
D_Aff8Patch (currententity->colormap);
#endif
}
acolormap = currententity->colormap;
if (r_pixbytes == 2)
acolormap = vid.colormap16;
if (currententity == &cl.viewent[r_refdef.currentplayernum] || currententity->flags & Q2RF_DEPTHHACK)
ziscale = (float)0x8000 * (float)0x10000 * 3.0;
else
ziscale = (float)0x8000 * (float)0x10000;
if (currententity->trivial_accept)
R_AliasPrepareUnclippedPoints ();
else
R_AliasPreparePoints ();
}

247
engine/sw/r_aliasa.s Normal file
View file

@ -0,0 +1,247 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// r_aliasa.s
// x86 assembly-language Alias model transform and project code.
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"
//FIXME: rework the changes to stvert_t in.
#if 0//id386
.data
Lfloat_1: .single 1.0
Ltemp: .long 0
Lcoords: .long 0, 0, 0
.text
#define fv 12+4
#if 0
#define pstverts 12+8
#endif
.globl C(R_AliasTransformAndProjectFinalVerts)
C(R_AliasTransformAndProjectFinalVerts):
#if 0
pushl %ebp // preserve caller's stack frame
#endif
pushl %edi
pushl %esi // preserve register variables
// int i, temp;
// float lightcos, *plightnormal, zi;
// trivertx_t *pverts;
// pverts = r_apverts;
movl C(r_apnewverts),%esi
// for (i=0 ; i<r_anumverts ; i++, fv++, pverts++)
// {
#if 0
movl pstverts(%esp),%ebp
#endif
movl fv(%esp),%edi
movl C(r_anumverts),%ecx
subl %edx,%edx
Lloop:
// // transform and project
// zi = 1.0 / (DotProduct(pverts->v, aliastransform[2]) +
// aliastransform[2][3]);
movb (%esi),%dl
movb %dl,Lcoords
fildl Lcoords // v[0]
movb 1(%esi),%dl
movb %dl,Lcoords+4
fildl Lcoords+4 // v[1] | v[0]
movb 2(%esi),%dl
movb %dl,Lcoords+8
fildl Lcoords+8 // v[2] | v[1] | v[0]
fld %st(2) // v[0] | v[2] | v[1] | v[0]
fmuls C(aliastransform)+32 // accum | v[2] | v[1] | v[0]
fld %st(2) // v[1] | accum | v[2] | v[1] | v[0]
fmuls C(aliastransform)+36 // accum2 | accum | v[2] | v[1] | v[0]
fxch %st(1) // accum | accum2 | v[2] | v[1] | v[0]
fadds C(aliastransform)+44 // accum | accum2 | v[2] | v[1] | v[0]
fld %st(2) // v[2] | accum | accum2 | v[2] | v[1] | v[0]
fmuls C(aliastransform)+40 // accum3 | accum | accum2 | v[2] | v[1] |
// v[0]
fxch %st(1) // accum | accum3 | accum2 | v[2] | v[1] | v[0]
faddp %st(0),%st(2) // accum3 | accum | v[2] | v[1] | v[0]
movb tv_lightnormalindex(%esi),%dl
movl stv_s(%ebp),%eax
movl %eax,fv_v+8(%edi)
faddp %st(0),%st(1) // z | v[2] | v[1] | v[0]
movl stv_t(%ebp),%eax
movl %eax,fv_v+12(%edi)
// // lighting
// plightnormal = r_avertexnormals[pverts->lightnormalindex];
fdivrs Lfloat_1 // zi | v[2] | v[1] | v[0]
#if 0
// fv->v[2] = pstverts->s;
// fv->v[3] = pstverts->t;
// fv->flags = pstverts->onseam;
movl stv_onseam(%ebp),%eax
movl %eax,fv_flags(%edi)
movl fv_size(%edi),%eax
movl stv_size(%ebp),%eax
movl 4(%esi),%eax
leal (%edx,%edx,2),%eax // index*3
fxch %st(3) // v[0] | v[2] | v[1] | zi
#endif
// lightcos = DotProduct (plightnormal, r_plightvec);
flds C(r_avertexnormals)(,%eax,4)
fmuls C(r_plightvec)
flds C(r_avertexnormals)+4(,%eax,4)
fmuls C(r_plightvec)+4
flds C(r_avertexnormals)+8(,%eax,4)
fmuls C(r_plightvec)+8
fxch %st(1)
faddp %st(0),%st(2)
fld %st(2) // v[0] | laccum | laccum2 | v[0] | v[2] |
// v[1] | zi
fmuls C(aliastransform)+0 // xaccum | laccum | laccum2 | v[0] | v[2] |
// v[1] | zi
fxch %st(2) // laccum2 | laccum | xaccum | v[0] | v[2] |
// v[1] | zi
faddp %st(0),%st(1) // laccum | xaccum | v[0] | v[2] | v[1] | zi
// temp = r_ambientlight;
// if (lightcos < 0)
// {
fsts Ltemp
movl C(r_ambientlight),%eax
movb Ltemp+3,%dl
testb $0x80,%dl
jz Lsavelight // no need to clamp if only ambient lit, because
// r_ambientlight is preclamped
// temp += (int)(r_shadelight * lightcos);
fmuls C(r_shadelight)
// FIXME: fast float->int conversion?
fistpl Ltemp
addl Ltemp,%eax
// // clamp; because we limited the minimum ambient and shading light, we
// // don't have to clamp low light, just bright
// if (temp < 0)
// temp = 0;
jns Lp1
subl %eax,%eax
// }
Lp1:
// fv->v[4] = temp;
//
// // x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is
// // scaled up by 1/2**31, and the scaling cancels out for x and y in the
// // projection
// fv->v[0] = ((DotProduct(pverts->v, aliastransform[0]) +
// aliastransform[0][3]) * zi) + aliasxcenter;
// fv->v[1] = ((DotProduct(pverts->v, aliastransform[1]) +
// aliastransform[1][3]) * zi) + aliasycenter;
// fv->v[5] = zi;
fxch %st(1) // v[0] | xaccum | v[2] | v[1] | zi
fmuls C(aliastransform)+16 // yaccum | xaccum | v[2] | v[1] | zi
fxch %st(3) // v[1] | xaccum | v[2] | yaccum | zi
fld %st(0) // v[1] | v[1] | xaccum | v[2] | yaccum | zi
fmuls C(aliastransform)+4 // xaccum2 | v[1] | xaccum | v[2] | yaccum |zi
fxch %st(1) // v[1] | xaccum2 | xaccum | v[2] | yaccum |zi
movl %eax,fv_v+16(%edi)
fmuls C(aliastransform)+20 // yaccum2 | xaccum2 | xaccum | v[2] | yaccum|
// zi
fxch %st(2) // xaccum | xaccum2 | yaccum2 | v[2] | yaccum|
// zi
fadds C(aliastransform)+12 // xaccum | xaccum2 | yaccum2 | v[2] | yaccum|
// zi
fxch %st(4) // yaccum | xaccum2 | yaccum2 | v[2] | xaccum|
// zi
fadds C(aliastransform)+28 // yaccum | xaccum2 | yaccum2 | v[2] | xaccum|
// zi
fxch %st(3) // v[2] | xaccum2 | yaccum2 | yaccum | xaccum|
// zi
fld %st(0) // v[2] | v[2] | xaccum2 | yaccum2 | yaccum |
// xaccum | zi
fmuls C(aliastransform)+8 // xaccum3 | v[2] | xaccum2 | yaccum2 |yaccum|
// xaccum | zi
fxch %st(1) // v[2] | xaccum3 | xaccum2 | yaccum2 |yaccum|
// xaccum | zi
fmuls C(aliastransform)+24 // yaccum3 | xaccum3 | xaccum2 | yaccum2 |
// yaccum | xaccum | zi
fxch %st(5) // xaccum | xaccum3 | xaccum2 | yaccum2 |
// yaccum | yaccum3 | zi
faddp %st(0),%st(2) // xaccum3 | xaccum | yaccum2 | yaccum |
// yaccum3 | zi
fxch %st(3) // yaccum | xaccum | yaccum2 | xaccum3 |
// yaccum3 | zi
faddp %st(0),%st(2) // xaccum | yaccum | xaccum3 | yaccum3 | zi
addl $(tv_size),%esi
faddp %st(0),%st(2) // yaccum | x | yaccum3 | zi
faddp %st(0),%st(2) // x | y | zi
addl $(stv_size),%ebp
fmul %st(2),%st(0) // x/z | y | zi
fxch %st(1) // y | x/z | zi
fmul %st(2),%st(0) // y/z | x/z | zi
fxch %st(1) // x/z | y/z | zi
fadds C(aliasxcenter) // u | y/z | zi
fxch %st(1) // y/z | u | zi
fadds C(aliasycenter) // v | u | zi
fxch %st(2) // zi | u | v
// FIXME: fast float->int conversion?
fistpl fv_v+20(%edi) // u | v
fistpl fv_v+0(%edi) // v
fistpl fv_v+4(%edi)
// }
addl $(fv_size),%edi
decl %ecx
jnz Lloop
popl %esi // restore register variables
popl %edi
#if 0
// popl %ebp // restore the caller's stack frame
#endif
ret
Lsavelight:
fstp %st(0)
jmp Lp1
#endif // id386

907
engine/sw/r_bsp.c Normal file
View file

@ -0,0 +1,907 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_bsp.c
#include "quakedef.h"
#include "r_local.h"
//
// current entity info
//
qboolean insubmodel;
entity_t *currententity;
vec3_t modelorg, base_modelorg;
// modelorg is the viewpoint reletive to
// the currently rendering entity
vec3_t r_entorigin; // the currently rendering entity in world
// coordinates
float entity_rotation[3][3];
vec3_t r_worldmodelorg;
int r_currentbkey;
typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t;
#define MAX_BMODEL_VERTS 500 // 6K
#define MAX_BMODEL_EDGES 1000 // 12K
static mvertex_t *pbverts;
static bedge_t *pbedges;
static int numbverts, numbedges;
static mvertex_t *pfrontenter, *pfrontexit;
static qboolean makeclippededge;
//===========================================================================
/*
================
R_EntityRotate
================
*/
void R_EntityRotate (vec3_t vec)
{
vec3_t tvec;
VectorCopy (vec, tvec);
vec[0] = DotProduct (entity_rotation[0], tvec);
vec[1] = DotProduct (entity_rotation[1], tvec);
vec[2] = DotProduct (entity_rotation[2], tvec);
}
/*
================
R_RotateBmodel
================
*/
void R_RotateBmodel (void)
{
float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
// TODO: should use a look-up table
// TODO: should really be stored with the entity instead of being reconstructed
// TODO: could cache lazily, stored in the entity
// TODO: share work with R_SetUpAliasTransform
// yaw
angle = currententity->angles[YAW];
angle = angle * M_PI*2 / 360;
s = sin(angle);
c = cos(angle);
temp1[0][0] = c;
temp1[0][1] = s;
temp1[0][2] = 0;
temp1[1][0] = -s;
temp1[1][1] = c;
temp1[1][2] = 0;
temp1[2][0] = 0;
temp1[2][1] = 0;
temp1[2][2] = 1;
// pitch
angle = currententity->angles[PITCH];
angle = angle * M_PI*2 / 360;
s = sin(angle);
c = cos(angle);
temp2[0][0] = c;
temp2[0][1] = 0;
temp2[0][2] = -s;
temp2[1][0] = 0;
temp2[1][1] = 1;
temp2[1][2] = 0;
temp2[2][0] = s;
temp2[2][1] = 0;
temp2[2][2] = c;
R_ConcatRotations (temp2, temp1, temp3);
// roll
angle = currententity->angles[ROLL];
angle = angle * M_PI*2 / 360;
s = sin(angle);
c = cos(angle);
temp1[0][0] = 1;
temp1[0][1] = 0;
temp1[0][2] = 0;
temp1[1][0] = 0;
temp1[1][1] = c;
temp1[1][2] = s;
temp1[2][0] = 0;
temp1[2][1] = -s;
temp1[2][2] = c;
R_ConcatRotations (temp1, temp3, entity_rotation);
//
// rotate modelorg and the transformation matrix
//
R_EntityRotate (modelorg);
R_EntityRotate (vpn);
R_EntityRotate (vright);
R_EntityRotate (vup);
R_TransformFrustum ();
}
/*
================
R_RecursiveClipBPoly
================
*/
void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
{
bedge_t *psideedges[2], *pnextedge, *ptedge;
int i, side, lastside;
float dist, frac, lastdist;
mplane_t *splitplane, tplane;
mvertex_t *pvert, *plastvert, *ptvert;
mnode_t *pn;
psideedges[0] = psideedges[1] = NULL;
makeclippededge = false;
// transform the BSP plane into model space
// FIXME: cache these?
splitplane = pnode->plane;
if (!splitplane)
return;
tplane.dist = splitplane->dist -
DotProduct(r_entorigin, splitplane->normal);
tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
// clip edges to BSP plane
for ( ; pedges ; pedges = pnextedge)
{
pnextedge = pedges->pnext;
// set the status for the last point as the previous point
// FIXME: cache this stuff somehow?
plastvert = pedges->v[0];
lastdist = DotProduct (plastvert->position, tplane.normal) -
tplane.dist;
if (lastdist > 0)
lastside = 0;
else
lastside = 1;
pvert = pedges->v[1];
dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
if (dist > 0)
side = 0;
else
side = 1;
if (side != lastside)
{
// clipped
if (numbverts >= MAX_BMODEL_VERTS)
return;
// generate the clipped vertex
frac = lastdist / (lastdist - dist);
ptvert = &pbverts[numbverts++];
ptvert->position[0] = plastvert->position[0] +
frac * (pvert->position[0] -
plastvert->position[0]);
ptvert->position[1] = plastvert->position[1] +
frac * (pvert->position[1] -
plastvert->position[1]);
ptvert->position[2] = plastvert->position[2] +
frac * (pvert->position[2] -
plastvert->position[2]);
// split into two edges, one on each side, and remember entering
// and exiting points
// FIXME: share the clip edge by having a winding direction flag?
if (numbedges >= (MAX_BMODEL_EDGES - 1))
{
Con_Printf ("Out of edges for bmodel\n");
return;
}
ptedge = &pbedges[numbedges];
ptedge->pnext = psideedges[lastside];
psideedges[lastside] = ptedge;
ptedge->v[0] = plastvert;
ptedge->v[1] = ptvert;
ptedge = &pbedges[numbedges + 1];
ptedge->pnext = psideedges[side];
psideedges[side] = ptedge;
ptedge->v[0] = ptvert;
ptedge->v[1] = pvert;
numbedges += 2;
if (side == 0)
{
// entering for front, exiting for back
pfrontenter = ptvert;
makeclippededge = true;
}
else
{
pfrontexit = ptvert;
makeclippededge = true;
}
}
else
{
// add the edge to the appropriate side
pedges->pnext = psideedges[side];
psideedges[side] = pedges;
}
}
// if anything was clipped, reconstitute and add the edges along the clip
// plane to both sides (but in opposite directions)
if (makeclippededge)
{
if (numbedges >= (MAX_BMODEL_EDGES - 2))
{
Con_Printf ("Out of edges for bmodel\n");
return;
}
ptedge = &pbedges[numbedges];
ptedge->pnext = psideedges[0];
psideedges[0] = ptedge;
ptedge->v[0] = pfrontexit;
ptedge->v[1] = pfrontenter;
ptedge = &pbedges[numbedges + 1];
ptedge->pnext = psideedges[1];
psideedges[1] = ptedge;
ptedge->v[0] = pfrontenter;
ptedge->v[1] = pfrontexit;
numbedges += 2;
}
// draw or recurse further
for (i=0 ; i<2 ; i++)
{
if (psideedges[i])
{
// draw if we've reached a non-solid leaf, done if all that's left is a
// solid leaf, and continue down the tree if it's not a leaf
pn = pnode->children[i];
// we're done with this branch if the node or leaf isn't in the PVS
if (pn->visframe == r_visframecount)
{
if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)
{
if (pn->contents != -1)
{
if (pn->contents != Q2CONTENTS_SOLID)
{
r_currentbkey = ((mleaf_t *)pn)->key;
R_RenderBmodelFace (psideedges[i], psurf);
}
}
else
{
R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
psurf);
}
}
else
{
if (pn->contents < 0)
{
if (pn->contents != Q1CONTENTS_SOLID)
{
r_currentbkey = ((mleaf_t *)pn)->key;
R_RenderBmodelFace (psideedges[i], psurf);
}
}
else
{
R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
psurf);
}
}
}
}
}
}
/*
================
R_DrawSolidClippedSubmodelPolygons
================
*/
void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel)
{
int i, j, lindex;
vec_t dot;
msurface_t *psurf;
int numsurfaces;
mplane_t *pplane;
mvertex_t bverts[MAX_BMODEL_VERTS];
bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
medge_t *pedge, *pedges;
// FIXME: use bounding-box-based frustum clipping info?
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
numsurfaces = pmodel->nummodelsurfaces;
pedges = pmodel->edges;
for (i=0 ; i<numsurfaces ; i++, psurf++)
{
// find which side of the node we are on
pplane = psurf->plane;
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
// draw the polygon
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
{
// FIXME: use bounding-box-based frustum clipping info?
// copy the edges to bedges, flipping if necessary so always
// clockwise winding
// FIXME: if edges and vertices get caches, these assignments must move
// outside the loop, and overflow checking must be done here
pbverts = bverts;
pbedges = bedges;
numbverts = numbedges = 0;
if (psurf->numedges > 0)
{
pbedge = &bedges[numbedges];
numbedges += psurf->numedges;
for (j=0 ; j<psurf->numedges ; j++)
{
lindex = pmodel->surfedges[psurf->firstedge+j];
if (lindex > 0)
{
pedge = &pedges[lindex];
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
}
else
{
lindex = -lindex;
pedge = &pedges[lindex];
pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
}
pbedge[j].pnext = &pbedge[j+1];
}
pbedge[j-1].pnext = NULL; // mark end of edges
R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf);
}
else
{
Sys_Error ("no edges in bmodel");
}
}
}
}
/*
================
R_DrawSubmodelPolygons
================
*/
void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags)
{
int i;
vec_t dot;
msurface_t *psurf;
int numsurfaces;
mplane_t *pplane;
// FIXME: use bounding-box-based frustum clipping info?
psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
numsurfaces = pmodel->nummodelsurfaces;
for (i=0 ; i<numsurfaces ; i++, psurf++)
{
// find which side of the node we are on
pplane = psurf->plane;
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
// draw the polygon
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
{
r_currentkey = ((mleaf_t *)currententity->topnode)->key;
// FIXME: use bounding-box-based frustum clipping info?
R_RenderFace (psurf, clipflags);
}
}
}
/*
================
R_RecursiveWorldNode
================
*/
void SWR_RecursiveWorldNode (mnode_t *node, int clipflags)
{
int i, c, side, *pindex;
vec3_t acceptpt, rejectpt;
mplane_t *plane;
msurface_t *surf, **mark;
mleaf_t *pleaf;
double d, dot;
if (node->contents == Q1CONTENTS_SOLID)
return; // solid
if (node->visframe != r_visframecount)
return;
// cull the clipping planes if not trivial accept
// FIXME: the compiler is doing a lousy job of optimizing here; it could be
// twice as fast in ASM
if (clipflags)
{
for (i=0 ; i<4 ; i++)
{
if (! (clipflags & (1<<i)) )
continue; // don't need to clip against it
// generate accept and reject points
// FIXME: do with fast look-ups or integer tests based on the sign bit
// of the floating point values
pindex = pfrustum_indexes[i];
rejectpt[0] = (float)node->minmaxs[pindex[0]];
rejectpt[1] = (float)node->minmaxs[pindex[1]];
rejectpt[2] = (float)node->minmaxs[pindex[2]];
d = DotProduct (rejectpt, view_clipplanes[i].normal);
d -= view_clipplanes[i].dist;
if (d <= 0)
return;
acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
d = DotProduct (acceptpt, view_clipplanes[i].normal);
d -= view_clipplanes[i].dist;
if (d >= 0)
clipflags &= ~(1<<i); // node is entirely on screen
}
}
// if a leaf node, draw stuff
if (node->contents < 0)
{
pleaf = (mleaf_t *)node;
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
if (c)
{
do
{
(*mark)->visframe = r_framecount;
mark++;
} while (--c);
}
// deal with model fragments in this leaf
if (pleaf->efrags)
{
R_StoreEfrags (&pleaf->efrags);
}
pleaf->key = r_currentkey;
r_currentkey++; // all bmodels in a leaf share the same key
}
else
{
// node is just a decision point, so go down the apropriate sides
// find which side of the node we are on
plane = node->plane;
switch (plane->type)
{
case PLANE_X:
dot = modelorg[0] - plane->dist;
break;
case PLANE_Y:
dot = modelorg[1] - plane->dist;
break;
case PLANE_Z:
dot = modelorg[2] - plane->dist;
break;
default:
dot = DotProduct (modelorg, plane->normal) - plane->dist;
break;
}
if (dot >= 0)
side = 0;
else
side = 1;
// recurse down the children, front side first
SWR_RecursiveWorldNode (node->children[side], clipflags);
// draw stuff
c = node->numsurfaces;
if (c)
{
surf = cl.worldmodel->surfaces + node->firstsurface;
if (dot < -BACKFACE_EPSILON)
{
do
{
if ((surf->flags & SURF_PLANEBACK) &&
(surf->visframe == r_framecount))
{
if (r_drawpolys)
{
if (r_worldpolysbacktofront)
{
if (numbtofpolys < MAX_BTOFPOLYS)
{
pbtofpolys[numbtofpolys].clipflags =
clipflags;
pbtofpolys[numbtofpolys].psurf = surf;
numbtofpolys++;
}
}
else
{
R_RenderPoly (surf, clipflags);
}
}
else
{
R_RenderFace (surf, clipflags);
}
}
surf++;
} while (--c);
}
else if (dot > BACKFACE_EPSILON)
{
do
{
if (!(surf->flags & SURF_PLANEBACK) &&
(surf->visframe == r_framecount))
{
if (r_drawpolys)
{
if (r_worldpolysbacktofront)
{
if (numbtofpolys < MAX_BTOFPOLYS)
{
pbtofpolys[numbtofpolys].clipflags =
clipflags;
pbtofpolys[numbtofpolys].psurf = surf;
numbtofpolys++;
}
}
else
{
R_RenderPoly (surf, clipflags);
}
}
else
{
R_RenderFace (surf, clipflags);
}
}
surf++;
} while (--c);
}
// all surfaces on the same node share the same sequence number
r_currentkey++;
}
// recurse down the back side
SWR_RecursiveWorldNode (node->children[!side], clipflags);
}
}
qbyte areabits[MAX_Q2MAP_AREAS/8];
void SWR_RecursiveQ2WorldNode (mnode_t *node, int clipflags)
{
int i, c, side, *pindex;
vec3_t acceptpt, rejectpt;
mplane_t *plane;
msurface_t *surf, **mark;
mleaf_t *pleaf;
double d, dot;
if (node->contents == Q2CONTENTS_SOLID)
return; // solid
if (node->visframe != r_visframecount)
return;
// cull the clipping planes if not trivial accept
// FIXME: the compiler is doing a lousy job of optimizing here; it could be
// twice as fast in ASM
if (clipflags)
{
for (i=0 ; i<4 ; i++)
{
if (! (clipflags & (1<<i)) )
continue; // don't need to clip against it
// generate accept and reject points
// FIXME: do with fast look-ups or integer tests based on the sign bit
// of the floating point values
pindex = pfrustum_indexes[i];
rejectpt[0] = (float)node->minmaxs[pindex[0]];
rejectpt[1] = (float)node->minmaxs[pindex[1]];
rejectpt[2] = (float)node->minmaxs[pindex[2]];
d = DotProduct (rejectpt, view_clipplanes[i].normal);
d -= view_clipplanes[i].dist;
if (d <= 0)
return;
acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
d = DotProduct (acceptpt, view_clipplanes[i].normal);
d -= view_clipplanes[i].dist;
if (d >= 0)
clipflags &= ~(1<<i); // node is entirely on screen
}
}
// if a leaf node, draw stuff
if (node->contents != -1)
{
pleaf = (mleaf_t *)node;
// check for door connected areas
// if (areabits)
// {
if (! (areabits[pleaf->area>>3] & (1<<(pleaf->area&7)) ) )
return; // not visible
// }
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
if (c)
{
do
{
(*mark)->visframe = r_framecount;
mark++;
} while (--c);
}
pleaf->key = r_currentkey;
r_currentkey++; // all bmodels in a leaf share the same key
}
else
{
// node is just a decision point, so go down the apropriate sides
// find which side of the node we are on
plane = node->plane;
switch (plane->type)
{
case PLANE_X:
dot = modelorg[0] - plane->dist;
break;
case PLANE_Y:
dot = modelorg[1] - plane->dist;
break;
case PLANE_Z:
dot = modelorg[2] - plane->dist;
break;
default:
dot = DotProduct (modelorg, plane->normal) - plane->dist;
break;
}
if (dot >= 0)
side = 0;
else
side = 1;
// recurse down the children, front side first
SWR_RecursiveQ2WorldNode (node->children[side], clipflags);
// draw stuff
c = node->numsurfaces;
if (c)
{
surf = cl.worldmodel->surfaces + node->firstsurface;
if (dot < -BACKFACE_EPSILON)
{
do
{
if ((surf->flags & SURF_PLANEBACK) &&
(surf->visframe == r_framecount))
{
if (r_drawpolys)
{
if (r_worldpolysbacktofront)
{
if (numbtofpolys < MAX_BTOFPOLYS)
{
pbtofpolys[numbtofpolys].clipflags =
clipflags;
pbtofpolys[numbtofpolys].psurf = surf;
numbtofpolys++;
}
}
else
{
R_RenderPoly (surf, clipflags);
}
}
else
{
R_RenderFace (surf, clipflags);
}
}
surf++;
} while (--c);
}
else if (dot > BACKFACE_EPSILON)
{
do
{
if (!(surf->flags & SURF_PLANEBACK) &&
(surf->visframe == r_framecount))
{
if (r_drawpolys)
{
if (r_worldpolysbacktofront)
{
if (numbtofpolys < MAX_BTOFPOLYS)
{
pbtofpolys[numbtofpolys].clipflags =
clipflags;
pbtofpolys[numbtofpolys].psurf = surf;
numbtofpolys++;
}
}
else
{
R_RenderPoly (surf, clipflags);
}
}
else
{
R_RenderFace (surf, clipflags);
}
}
surf++;
} while (--c);
}
// all surfaces on the same node share the same sequence number
r_currentkey++;
}
// recurse down the back side
SWR_RecursiveQ2WorldNode (node->children[!side], clipflags);
}
}
/*
================
R_RenderWorld
================
*/
void R_RenderWorld (void)
{
int i;
model_t *clmodel;
btofpoly_t btofpolys[MAX_BTOFPOLYS];
pbtofpolys = btofpolys;
currententity = &r_worldentity;
VectorCopy (r_origin, modelorg);
clmodel = currententity->model;
r_pcurrentvertbase = clmodel->vertexes;
if (clmodel->fromgame == fg_quake2)
{
int leafnum;
int clientarea;
int CM_WriteAreaBits (qbyte *buffer, int area);
if (cls.q2server)
memcpy(areabits, cl.q2frame.areabits, sizeof(areabits));
else
{
leafnum = CM_PointLeafnum (r_refdef.vieworg);
clientarea = CM_LeafArea (leafnum);
CM_WriteAreaBits(areabits, clientarea);
}
SWR_RecursiveQ2WorldNode (clmodel->nodes, 15);
}
else
SWR_RecursiveWorldNode (clmodel->nodes, 15);
// if the driver wants the polygons back to front, play the visible ones back
// in that order
if (r_worldpolysbacktofront)
{
for (i=numbtofpolys-1 ; i>=0 ; i--)
{
R_RenderPoly (btofpolys[i].psurf, btofpolys[i].clipflags);
}
}
}

2696
engine/sw/r_draw.c Normal file

File diff suppressed because it is too large Load diff

838
engine/sw/r_drawa.s Normal file
View file

@ -0,0 +1,838 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// r_drawa.s
// x86 assembly-language edge clipping and emission code
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"
#if id386
// !!! if these are changed, they must be changed in r_draw.c too !!!
#define FULLY_CLIPPED_CACHED 0x80000000
#define FRAMECOUNT_MASK 0x7FFFFFFF
.data
Ld0: .single 0.0
Ld1: .single 0.0
Lstack: .long 0
Lfp_near_clip: .single NEAR_CLIP
Lceilv0: .long 0
Lv: .long 0
Lu0: .long 0
Lv0: .long 0
Lzi0: .long 0
.text
//----------------------------------------------------------------------
// edge clipping code
//----------------------------------------------------------------------
#define pv0 4+12
#define pv1 8+12
#define clip 12+12
.align 4
.globl C(R_ClipEdge)
C(R_ClipEdge):
pushl %esi // preserve register variables
pushl %edi
pushl %ebx
movl %esp,Lstack // for clearing the stack later
// float d0, d1, f;
// mvertex_t clipvert;
movl clip(%esp),%ebx
movl pv0(%esp),%esi
movl pv1(%esp),%edx
// if (clip)
// {
testl %ebx,%ebx
jz Lemit
// do
// {
Lcliploop:
// d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
// d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
flds mv_position+0(%esi)
fmuls cp_normal+0(%ebx)
flds mv_position+4(%esi)
fmuls cp_normal+4(%ebx)
flds mv_position+8(%esi)
fmuls cp_normal+8(%ebx)
fxch %st(1)
faddp %st(0),%st(2) // d0mul2 | d0add0
flds mv_position+0(%edx)
fmuls cp_normal+0(%ebx)
flds mv_position+4(%edx)
fmuls cp_normal+4(%ebx)
flds mv_position+8(%edx)
fmuls cp_normal+8(%ebx)
fxch %st(1)
faddp %st(0),%st(2) // d1mul2 | d1add0 | d0mul2 | d0add0
fxch %st(3) // d0add0 | d1add0 | d0mul2 | d1mul2
faddp %st(0),%st(2) // d1add0 | dot0 | d1mul2
faddp %st(0),%st(2) // dot0 | dot1
fsubs cp_dist(%ebx) // d0 | dot1
fxch %st(1) // dot1 | d0
fsubs cp_dist(%ebx) // d1 | d0
fxch %st(1)
fstps Ld0
fstps Ld1
// if (d0 >= 0)
// {
movl Ld0,%eax
movl Ld1,%ecx
orl %eax,%ecx
js Lp2
// both points are unclipped
Lcontinue:
//
// R_ClipEdge (&clipvert, pv1, clip->next);
// return;
// }
// } while ((clip = clip->next) != NULL);
movl cp_next(%ebx),%ebx
testl %ebx,%ebx
jnz Lcliploop
// }
//// add the edge
// R_EmitEdge (pv0, pv1);
Lemit:
//
// set integer rounding to ceil mode, set to single precision
//
// FIXME: do away with by manually extracting integers from floats?
// FIXME: set less often
fldcw ceil_cw
// edge_t *edge, *pcheck;
// int u_check;
// float u, u_step;
// vec3_t local, transformed;
// float *world;
// int v, v2, ceilv0;
// float scale, lzi0, u0, v0;
// int side;
// if (r_lastvertvalid)
// {
cmpl $0,C(r_lastvertvalid)
jz LCalcFirst
// u0 = r_u1;
// v0 = r_v1;
// lzi0 = r_lzi1;
// ceilv0 = r_ceilv1;
movl C(r_lzi1),%eax
movl C(r_u1),%ecx
movl %eax,Lzi0
movl %ecx,Lu0
movl C(r_v1),%ecx
movl C(r_ceilv1),%eax
movl %ecx,Lv0
movl %eax,Lceilv0
jmp LCalcSecond
// }
LCalcFirst:
// else
// {
// world = &pv0->position[0];
call LTransformAndProject // v0 | lzi0 | u0
fsts Lv0
fxch %st(2) // u0 | lzi0 | v0
fstps Lu0 // lzi0 | v0
fstps Lzi0 // v0
// ceilv0 = (int)(v0 - 2000) + 2000; // ceil(v0);
fistpl Lceilv0
// }
LCalcSecond:
// world = &pv1->position[0];
movl %edx,%esi
call LTransformAndProject // v1 | lzi1 | u1
flds Lu0 // u0 | v1 | lzi1 | u1
fxch %st(3) // u1 | v1 | lzi1 | u0
flds Lzi0 // lzi0 | u1 | v1 | lzi1 | u0
fxch %st(3) // lzi1 | u1 | v1 | lzi0 | u0
flds Lv0 // v0 | lzi1 | u1 | v1 | lzi0 | u0
fxch %st(3) // v1 | lzi1 | u1 | v0 | lzi0 | u0
// r_ceilv1 = (int)(r_v1 - 2000) + 2000; // ceil(r_v1);
fistl C(r_ceilv1)
fldcw single_cw // put back normal floating-point state
fsts C(r_v1)
fxch %st(4) // lzi0 | lzi1 | u1 | v0 | v1 | u0
// if (r_lzi1 > lzi0)
// lzi0 = r_lzi1;
fcom %st(1)
fnstsw %ax
testb $1,%ah
jz LP0
fstp %st(0)
fld %st(0)
LP0:
fxch %st(1) // lzi1 | lzi0 | u1 | v0 | v1 | u0
fstps C(r_lzi1) // lzi0 | u1 | v0 | v1 | u0
fxch %st(1)
fsts C(r_u1)
fxch %st(1)
// if (lzi0 > r_nearzi) // for mipmap finding
// r_nearzi = lzi0;
fcoms C(r_nearzi)
fnstsw %ax
testb $0x45,%ah
jnz LP1
fsts C(r_nearzi)
LP1:
// // for right edges, all we want is the effect on 1/z
// if (r_nearzionly)
// return;
movl C(r_nearzionly),%eax
testl %eax,%eax
jz LP2
LPop5AndDone:
movl C(cacheoffset),%eax
movl C(r_framecount),%edx
cmpl $0x7FFFFFFF,%eax
jz LDoPop
andl $(FRAMECOUNT_MASK),%edx
orl $(FULLY_CLIPPED_CACHED),%edx
movl %edx,C(cacheoffset)
LDoPop:
fstp %st(0) // u1 | v0 | v1 | u0
fstp %st(0) // v0 | v1 | u0
fstp %st(0) // v1 | u0
fstp %st(0) // u0
fstp %st(0)
jmp Ldone
LP2:
// // create the edge
// if (ceilv0 == r_ceilv1)
// return; // horizontal edge
movl Lceilv0,%ebx
movl C(edge_p),%edi
movl C(r_ceilv1),%ecx
movl %edi,%edx
movl C(r_pedge),%esi
addl $(et_size),%edx
cmpl %ecx,%ebx
jz LPop5AndDone
movl C(r_pedge),%eax
movl %eax,et_owner(%edi)
// side = ceilv0 > r_ceilv1;
//
// edge->nearzi = lzi0;
fstps et_nearzi(%edi) // u1 | v0 | v1 | u0
// if (side == 1)
// {
jc LSide0
LSide1:
// // leading edge (go from p2 to p1)
// u_step = ((u0 - r_u1) / (v0 - r_v1));
fsubrp %st(0),%st(3) // v0 | v1 | u0-u1
fsub %st(1),%st(0) // v0-v1 | v1 | u0-u1
fdivrp %st(0),%st(2) // v1 | ustep
// r_emitted = 1;
movl $1,C(r_emitted)
// edge = edge_p++;
movl %edx,C(edge_p)
// pretouch next edge
movl (%edx),%eax
// v2 = ceilv0 - 1;
// v = r_ceilv1;
movl %ecx,%eax
leal -1(%ebx),%ecx
movl %eax,%ebx
// edge->surfs[0] = 0;
// edge->surfs[1] = surface_p - surfaces;
movl C(surface_p),%eax
movl C(surfaces),%esi
subl %edx,%edx
subl %esi,%eax
shrl $(SURF_T_SHIFT),%eax
movl %edx,et_surfs(%edi)
movl %eax,et_surfs+2(%edi)
subl %esi,%esi
// u = r_u1 + ((float)v - r_v1) * u_step;
movl %ebx,Lv
fildl Lv // v | v1 | ustep
fsubp %st(0),%st(1) // v-v1 | ustep
fmul %st(1),%st(0) // (v-v1)*ustep | ustep
fadds C(r_u1) // u | ustep
jmp LSideDone
// }
LSide0:
// else
// {
// // trailing edge (go from p1 to p2)
// u_step = ((r_u1 - u0) / (r_v1 - v0));
fsub %st(3),%st(0) // u1-u0 | v0 | v1 | u0
fxch %st(2) // v1 | v0 | u1-u0 | u0
fsub %st(1),%st(0) // v1-v0 | v0 | u1-u0 | u0
fdivrp %st(0),%st(2) // v0 | ustep | u0
// r_emitted = 1;
movl $1,C(r_emitted)
// edge = edge_p++;
movl %edx,C(edge_p)
// pretouch next edge
movl (%edx),%eax
// v = ceilv0;
// v2 = r_ceilv1 - 1;
decl %ecx
// edge->surfs[0] = surface_p - surfaces;
// edge->surfs[1] = 0;
movl C(surface_p),%eax
movl C(surfaces),%esi
subl %edx,%edx
subl %esi,%eax
shrl $(SURF_T_SHIFT),%eax
movl %edx,et_surfs+2(%edi)
movl %eax,et_surfs(%edi)
movl $1,%esi
// u = u0 + ((float)v - v0) * u_step;
movl %ebx,Lv
fildl Lv // v | v0 | ustep | u0
fsubp %st(0),%st(1) // v-v0 | ustep | u0
fmul %st(1),%st(0) // (v-v0)*ustep | ustep | u0
faddp %st(0),%st(2) // ustep | u
fxch %st(1) // u | ustep
// }
LSideDone:
// edge->u_step = u_step*0x100000;
// edge->u = u*0x100000 + 0xFFFFF;
fmuls fp_1m // u*0x100000 | ustep
fxch %st(1) // ustep | u*0x100000
fmuls fp_1m // ustep*0x100000 | u*0x100000
fxch %st(1) // u*0x100000 | ustep*0x100000
fadds fp_1m_minus_1 // u*0x100000 + 0xFFFFF | ustep*0x100000
fxch %st(1) // ustep*0x100000 | u*0x100000 + 0xFFFFF
fistpl et_u_step(%edi) // u*0x100000 + 0xFFFFF
fistpl et_u(%edi)
// // we need to do this to avoid stepping off the edges if a very nearly
// // horizontal edge is less than epsilon above a scan, and numeric error
// // causes it to incorrectly extend to the scan, and the extension of the
// // line goes off the edge of the screen
// // FIXME: is this actually needed?
// if (edge->u < r_refdef.vrect_x_adj_shift20)
// edge->u = r_refdef.vrect_x_adj_shift20;
// if (edge->u > r_refdef.vrectright_adj_shift20)
// edge->u = r_refdef.vrectright_adj_shift20;
movl et_u(%edi),%eax
movl C(r_refdef)+rd_vrect_x_adj_shift20,%edx
cmpl %edx,%eax
jl LP4
movl C(r_refdef)+rd_vrectright_adj_shift20,%edx
cmpl %edx,%eax
jng LP5
LP4:
movl %edx,et_u(%edi)
movl %edx,%eax
LP5:
// // sort the edge in normally
// u_check = edge->u;
//
// if (edge->surfs[0])
// u_check++; // sort trailers after leaders
addl %esi,%eax
// if (!newedges[v] || newedges[v]->u >= u_check)
// {
movl C(newedges)(,%ebx,4),%esi
testl %esi,%esi
jz LDoFirst
cmpl %eax,et_u(%esi)
jl LNotFirst
LDoFirst:
// edge->next = newedges[v];
// newedges[v] = edge;
movl %esi,et_next(%edi)
movl %edi,C(newedges)(,%ebx,4)
jmp LSetRemove
// }
LNotFirst:
// else
// {
// pcheck = newedges[v];
//
// while (pcheck->next && pcheck->next->u < u_check)
// pcheck = pcheck->next;
LFindInsertLoop:
movl %esi,%edx
movl et_next(%esi),%esi
testl %esi,%esi
jz LInsertFound
cmpl %eax,et_u(%esi)
jl LFindInsertLoop
LInsertFound:
// edge->next = pcheck->next;
// pcheck->next = edge;
movl %esi,et_next(%edi)
movl %edi,et_next(%edx)
// }
LSetRemove:
// edge->nextremove = removeedges[v2];
// removeedges[v2] = edge;
movl C(removeedges)(,%ecx,4),%eax
movl %edi,C(removeedges)(,%ecx,4)
movl %eax,et_nextremove(%edi)
Ldone:
movl Lstack,%esp // clear temporary variables from stack
popl %ebx // restore register variables
popl %edi
popl %esi
ret
// at least one point is clipped
Lp2:
testl %eax,%eax
jns Lp1
// else
// {
// // point 0 is clipped
// if (d1 < 0)
// {
movl Ld1,%eax
testl %eax,%eax
jns Lp3
// // both points are clipped
// // we do cache fully clipped edges
// if (!leftclipped)
movl C(r_leftclipped),%eax
movl C(r_pedge),%ecx
testl %eax,%eax
jnz Ldone
// r_pedge->framecount = r_framecount;
movl C(r_framecount),%eax
andl $(FRAMECOUNT_MASK),%eax
orl $(FULLY_CLIPPED_CACHED),%eax
movl %eax,C(cacheoffset)
// return;
jmp Ldone
// }
Lp1:
// // point 0 is unclipped
// if (d1 >= 0)
// {
// // both points are unclipped
// continue;
// // only point 1 is clipped
// f = d0 / (d0 - d1);
flds Ld0
flds Ld1
fsubr %st(1),%st(0)
// // we don't cache partially clipped edges
movl $0x7FFFFFFF,C(cacheoffset)
fdivrp %st(0),%st(1)
subl $(mv_size),%esp // allocate space for clipvert
// clipvert.position[0] = pv0->position[0] +
// f * (pv1->position[0] - pv0->position[0]);
// clipvert.position[1] = pv0->position[1] +
// f * (pv1->position[1] - pv0->position[1]);
// clipvert.position[2] = pv0->position[2] +
// f * (pv1->position[2] - pv0->position[2]);
flds mv_position+8(%edx)
fsubs mv_position+8(%esi)
flds mv_position+4(%edx)
fsubs mv_position+4(%esi)
flds mv_position+0(%edx)
fsubs mv_position+0(%esi) // 0 | 1 | 2
// replace pv1 with the clip point
movl %esp,%edx
movl cp_leftedge(%ebx),%eax
testb %al,%al
fmul %st(3),%st(0)
fxch %st(1) // 1 | 0 | 2
fmul %st(3),%st(0)
fxch %st(2) // 2 | 0 | 1
fmulp %st(0),%st(3) // 0 | 1 | 2
fadds mv_position+0(%esi)
fxch %st(1) // 1 | 0 | 2
fadds mv_position+4(%esi)
fxch %st(2) // 2 | 0 | 1
fadds mv_position+8(%esi)
fxch %st(1) // 0 | 2 | 1
fstps mv_position+0(%esp) // 2 | 1
fstps mv_position+8(%esp) // 1
fstps mv_position+4(%esp)
// if (clip->leftedge)
// {
jz Ltestright
// r_leftclipped = true;
// r_leftexit = clipvert;
movl $1,C(r_leftclipped)
movl mv_position+0(%esp),%eax
movl %eax,C(r_leftexit)+mv_position+0
movl mv_position+4(%esp),%eax
movl %eax,C(r_leftexit)+mv_position+4
movl mv_position+8(%esp),%eax
movl %eax,C(r_leftexit)+mv_position+8
jmp Lcontinue
// }
Ltestright:
// else if (clip->rightedge)
// {
testb %ah,%ah
jz Lcontinue
// r_rightclipped = true;
// r_rightexit = clipvert;
movl $1,C(r_rightclipped)
movl mv_position+0(%esp),%eax
movl %eax,C(r_rightexit)+mv_position+0
movl mv_position+4(%esp),%eax
movl %eax,C(r_rightexit)+mv_position+4
movl mv_position+8(%esp),%eax
movl %eax,C(r_rightexit)+mv_position+8
// }
//
// R_ClipEdge (pv0, &clipvert, clip->next);
// return;
// }
jmp Lcontinue
// }
Lp3:
// // only point 0 is clipped
// r_lastvertvalid = false;
movl $0,C(r_lastvertvalid)
// f = d0 / (d0 - d1);
flds Ld0
flds Ld1
fsubr %st(1),%st(0)
// // we don't cache partially clipped edges
movl $0x7FFFFFFF,C(cacheoffset)
fdivrp %st(0),%st(1)
subl $(mv_size),%esp // allocate space for clipvert
// clipvert.position[0] = pv0->position[0] +
// f * (pv1->position[0] - pv0->position[0]);
// clipvert.position[1] = pv0->position[1] +
// f * (pv1->position[1] - pv0->position[1]);
// clipvert.position[2] = pv0->position[2] +
// f * (pv1->position[2] - pv0->position[2]);
flds mv_position+8(%edx)
fsubs mv_position+8(%esi)
flds mv_position+4(%edx)
fsubs mv_position+4(%esi)
flds mv_position+0(%edx)
fsubs mv_position+0(%esi) // 0 | 1 | 2
movl cp_leftedge(%ebx),%eax
testb %al,%al
fmul %st(3),%st(0)
fxch %st(1) // 1 | 0 | 2
fmul %st(3),%st(0)
fxch %st(2) // 2 | 0 | 1
fmulp %st(0),%st(3) // 0 | 1 | 2
fadds mv_position+0(%esi)
fxch %st(1) // 1 | 0 | 2
fadds mv_position+4(%esi)
fxch %st(2) // 2 | 0 | 1
fadds mv_position+8(%esi)
fxch %st(1) // 0 | 2 | 1
fstps mv_position+0(%esp) // 2 | 1
fstps mv_position+8(%esp) // 1
fstps mv_position+4(%esp)
// replace pv0 with the clip point
movl %esp,%esi
// if (clip->leftedge)
// {
jz Ltestright2
// r_leftclipped = true;
// r_leftenter = clipvert;
movl $1,C(r_leftclipped)
movl mv_position+0(%esp),%eax
movl %eax,C(r_leftenter)+mv_position+0
movl mv_position+4(%esp),%eax
movl %eax,C(r_leftenter)+mv_position+4
movl mv_position+8(%esp),%eax
movl %eax,C(r_leftenter)+mv_position+8
jmp Lcontinue
// }
Ltestright2:
// else if (clip->rightedge)
// {
testb %ah,%ah
jz Lcontinue
// r_rightclipped = true;
// r_rightenter = clipvert;
movl $1,C(r_rightclipped)
movl mv_position+0(%esp),%eax
movl %eax,C(r_rightenter)+mv_position+0
movl mv_position+4(%esp),%eax
movl %eax,C(r_rightenter)+mv_position+4
movl mv_position+8(%esp),%eax
movl %eax,C(r_rightenter)+mv_position+8
// }
jmp Lcontinue
// %esi = vec3_t point to transform and project
// %edx preserved
LTransformAndProject:
// // transform and project
// VectorSubtract (world, modelorg, local);
flds mv_position+0(%esi)
fsubs C(modelorg)+0
flds mv_position+4(%esi)
fsubs C(modelorg)+4
flds mv_position+8(%esi)
fsubs C(modelorg)+8
fxch %st(2) // local[0] | local[1] | local[2]
// TransformVector (local, transformed);
//
// if (transformed[2] < NEAR_CLIP)
// transformed[2] = NEAR_CLIP;
//
// lzi0 = 1.0 / transformed[2];
fld %st(0) // local[0] | local[0] | local[1] | local[2]
fmuls C(vpn)+0 // zm0 | local[0] | local[1] | local[2]
fld %st(1) // local[0] | zm0 | local[0] | local[1] |
// local[2]
fmuls C(vright)+0 // xm0 | zm0 | local[0] | local[1] | local[2]
fxch %st(2) // local[0] | zm0 | xm0 | local[1] | local[2]
fmuls C(vup)+0 // ym0 | zm0 | xm0 | local[1] | local[2]
fld %st(3) // local[1] | ym0 | zm0 | xm0 | local[1] |
// local[2]
fmuls C(vpn)+4 // zm1 | ym0 | zm0 | xm0 | local[1] |
// local[2]
fld %st(4) // local[1] | zm1 | ym0 | zm0 | xm0 |
// local[1] | local[2]
fmuls C(vright)+4 // xm1 | zm1 | ym0 | zm0 | xm0 |
// local[1] | local[2]
fxch %st(5) // local[1] | zm1 | ym0 | zm0 | xm0 |
// xm1 | local[2]
fmuls C(vup)+4 // ym1 | zm1 | ym0 | zm0 | xm0 |
// xm1 | local[2]
fxch %st(1) // zm1 | ym1 | ym0 | zm0 | xm0 |
// xm1 | local[2]
faddp %st(0),%st(3) // ym1 | ym0 | zm2 | xm0 | xm1 | local[2]
fxch %st(3) // xm0 | ym0 | zm2 | ym1 | xm1 | local[2]
faddp %st(0),%st(4) // ym0 | zm2 | ym1 | xm2 | local[2]
faddp %st(0),%st(2) // zm2 | ym2 | xm2 | local[2]
fld %st(3) // local[2] | zm2 | ym2 | xm2 | local[2]
fmuls C(vpn)+8 // zm3 | zm2 | ym2 | xm2 | local[2]
fld %st(4) // local[2] | zm3 | zm2 | ym2 | xm2 | local[2]
fmuls C(vright)+8 // xm3 | zm3 | zm2 | ym2 | xm2 | local[2]
fxch %st(5) // local[2] | zm3 | zm2 | ym2 | xm2 | xm3
fmuls C(vup)+8 // ym3 | zm3 | zm2 | ym2 | xm2 | xm3
fxch %st(1) // zm3 | ym3 | zm2 | ym2 | xm2 | xm3
faddp %st(0),%st(2) // ym3 | zm4 | ym2 | xm2 | xm3
fxch %st(4) // xm3 | zm4 | ym2 | xm2 | ym3
faddp %st(0),%st(3) // zm4 | ym2 | xm4 | ym3
fxch %st(1) // ym2 | zm4 | xm4 | ym3
faddp %st(0),%st(3) // zm4 | xm4 | ym4
fcoms Lfp_near_clip
fnstsw %ax
testb $1,%ah
jz LNoClip
fstp %st(0)
flds Lfp_near_clip
LNoClip:
fdivrs float_1 // lzi0 | x | y
fxch %st(1) // x | lzi0 | y
// // FIXME: build x/yscale into transform?
// scale = xscale * lzi0;
// u0 = (xcenter + scale*transformed[0]);
flds C(xscale) // xscale | x | lzi0 | y
fmul %st(2),%st(0) // scale | x | lzi0 | y
fmulp %st(0),%st(1) // scale*x | lzi0 | y
fadds C(xcenter) // u0 | lzi0 | y
// if (u0 < r_refdef.fvrectx_adj)
// u0 = r_refdef.fvrectx_adj;
// if (u0 > r_refdef.fvrectright_adj)
// u0 = r_refdef.fvrectright_adj;
// FIXME: use integer compares of floats?
fcoms C(r_refdef)+rd_fvrectx_adj
fnstsw %ax
testb $1,%ah
jz LClampP0
fstp %st(0)
flds C(r_refdef)+rd_fvrectx_adj
LClampP0:
fcoms C(r_refdef)+rd_fvrectright_adj
fnstsw %ax
testb $0x45,%ah
jnz LClampP1
fstp %st(0)
flds C(r_refdef)+rd_fvrectright_adj
LClampP1:
fld %st(1) // lzi0 | u0 | lzi0 | y
// scale = yscale * lzi0;
// v0 = (ycenter - scale*transformed[1]);
fmuls C(yscale) // scale | u0 | lzi0 | y
fmulp %st(0),%st(3) // u0 | lzi0 | scale*y
fxch %st(2) // scale*y | lzi0 | u0
fsubrs C(ycenter) // v0 | lzi0 | u0
// if (v0 < r_refdef.fvrecty_adj)
// v0 = r_refdef.fvrecty_adj;
// if (v0 > r_refdef.fvrectbottom_adj)
// v0 = r_refdef.fvrectbottom_adj;
// FIXME: use integer compares of floats?
fcoms C(r_refdef)+rd_fvrecty_adj
fnstsw %ax
testb $1,%ah
jz LClampP2
fstp %st(0)
flds C(r_refdef)+rd_fvrecty_adj
LClampP2:
fcoms C(r_refdef)+rd_fvrectbottom_adj
fnstsw %ax
testb $0x45,%ah
jnz LClampP3
fstp %st(0)
flds C(r_refdef)+rd_fvrectbottom_adj
LClampP3:
ret
#endif // id386

931
engine/sw/r_edge.c Normal file
View file

@ -0,0 +1,931 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_edge.c
#include "quakedef.h"
#include "r_local.h"
#if 0
// FIXME
the complex cases add new polys on most lines, so dont optimize for keeping them the same
have multiple free span lists to try to get better coherence?
low depth complexity -- 1 to 3 or so
this breaks spans at every edge, even hidden ones (bad)
have a sentinal at both ends?
#endif
edge_t *auxedges;
edge_t *r_edges, *edge_p, *edge_max;
surf_t *surfaces, *surface_p, *surf_max;
// surfaces are generated in back to front order by the bsp, so if a surf
// pointer is greater than another one, it should be drawn in front
// surfaces[1] is the background, and is used as the active surface stack
edge_t *newedges[MAXHEIGHT];
edge_t *removeedges[MAXHEIGHT];
espan_t *span_p, *max_span_p;
int r_currentkey;
extern int screenwidth;
int current_iv;
int edge_head_u_shift20, edge_tail_u_shift20;
static void (*pdrawfunc)(void);
edge_t edge_head;
edge_t edge_tail;
edge_t edge_aftertail;
edge_t edge_sentinel;
float fv;
void R_GenerateSpans (void);
void R_GenerateSpansTrans (void);
void R_GenerateSpansBackward (void);
void R_LeadingEdge (edge_t *edge);
void R_LeadingEdgeBackwards (edge_t *edge);
void R_TrailingEdge (surf_t *surf, edge_t *edge);
//=============================================================================
/*
==============
R_DrawCulledPolys
==============
*/
void R_DrawCulledPolys (void)
{
surf_t *s;
msurface_t *pface;
currententity = &r_worldentity;
if (r_worldpolysbacktofront)
{
for (s=surface_p-1 ; s>&surfaces[1] ; s--)
{
if (!s->spans)
continue;
if (!(s->flags & SURF_DRAWBACKGROUND))
{
pface = (msurface_t *)s->data;
R_RenderPoly (pface, 15);
}
}
}
else
{
for (s = &surfaces[1] ; s<surface_p ; s++)
{
if (!s->spans)
continue;
if (!(s->flags & SURF_DRAWBACKGROUND))
{
pface = (msurface_t *)s->data;
R_RenderPoly (pface, 15);
}
}
}
}
/*
==============
R_BeginEdgeFrame
==============
*/
void R_BeginEdgeFrame (void)
{
int v;
edge_p = r_edges;
edge_max = &r_edges[r_numallocatededges];
surface_p = &surfaces[2]; // background is surface 1,
// surface 0 is a dummy
surfaces[1].spans = NULL; // no background spans yet
surfaces[1].flags = SURF_DRAWBACKGROUND;
// put the background behind everything in the world
if (r_draworder.value)
{
pdrawfunc = R_GenerateSpansBackward;
surfaces[1].key = 0;
r_currentkey = 1;
}
else if (cl.worldmodel->fromgame == fg_halflife)
{
pdrawfunc = R_GenerateSpansTrans;
surfaces[1].key = 0x7FFFFFFF;
r_currentkey = 0;
}
else
{
pdrawfunc = R_GenerateSpans;
surfaces[1].key = 0x7FFFFFFF;
r_currentkey = 0;
}
// FIXME: set with memset
for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
{
newedges[v] = removeedges[v] = NULL;
}
}
#if !id386
/*
==============
R_InsertNewEdges
Adds the edges in the linked list edgestoadd, adding them to the edges in the
linked list edgelist. edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]). edgelist is assumed to be sorted on u, with a
sentinel at the end (actually, this is the active edge table starting at
edge_head.next).
==============
*/
void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
{
edge_t *next_edge;
do
{
next_edge = edgestoadd->next;
edgesearch:
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
if (edgelist->u >= edgestoadd->u)
goto addedge;
edgelist=edgelist->next;
goto edgesearch;
// insert edgestoadd before edgelist
addedge:
edgestoadd->next = edgelist;
edgestoadd->prev = edgelist->prev;
edgelist->prev->next = edgestoadd;
edgelist->prev = edgestoadd;
} while ((edgestoadd = next_edge) != NULL);
}
#endif // !id386
#if !id386
/*
==============
R_RemoveEdges
==============
*/
void R_RemoveEdges (edge_t *pedge)
{
do
{
pedge->next->prev = pedge->prev;
pedge->prev->next = pedge->next;
} while ((pedge = pedge->nextremove) != NULL);
}
#endif // !id386
#if !id386
/*
==============
R_StepActiveU
==============
*/
void R_StepActiveU (edge_t *pedge)
{
edge_t *pnext_edge, *pwedge;
while (1)
{
nextedge:
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
pedge->u += pedge->u_step;
if (pedge->u < pedge->prev->u)
goto pushback;
pedge = pedge->next;
goto nextedge;
pushback:
if (pedge == &edge_aftertail)
return;
// push it back to keep it sorted
pnext_edge = pedge->next;
// pull the edge out of the edge list
pedge->next->prev = pedge->prev;
pedge->prev->next = pedge->next;
// find out where the edge goes in the edge list
pwedge = pedge->prev->prev;
while (pwedge->u > pedge->u)
{
pwedge = pwedge->prev;
}
// put the edge back into the edge list
pedge->next = pwedge->next;
pedge->prev = pwedge;
pedge->next->prev = pedge;
pwedge->next = pedge;
pedge = pnext_edge;
if (pedge == &edge_tail)
return;
}
}
#endif // !id386
/*
==============
R_CleanupSpan
==============
*/
void R_CleanupSpan (void)
{
surf_t *surf;
int iu;
espan_t *span;
// now that we've reached the right edge of the screen, we're done with any
// unfinished surfaces, so emit a span for whatever's on top
surf = surfaces[1].next;
iu = edge_tail_u_shift20;
if (iu > surf->last_u)
{
span = span_p++;
span->u = surf->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf->spans;
surf->spans = span;
}
// reset spanstate for all surfaces in the surface stack
do
{
surf->spanstate = 0;
surf = surf->next;
} while (surf != &surfaces[1]);
}
/*
==============
R_LeadingEdgeBackwards
==============
*/
void R_LeadingEdgeBackwards (edge_t *edge)
{
espan_t *span;
surf_t *surf, *surf2;
int iu;
// it's adding a new surface in, so find the correct place
surf = &surfaces[edge->surfs[1]];
// don't start a span if this is an inverted span, with the end
// edge preceding the start edge (that is, we've already seen the
// end edge)
if (++surf->spanstate == 1)
{
surf2 = surfaces[1].next;
if (surf->key > surf2->key)
goto newtop;
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (surf->insubmodel && (surf->key == surf2->key))
{
// must be two bmodels in the same leaf; don't care, because they'll
// never be farthest anyway
goto newtop;
}
continue_search:
do
{
surf2 = surf2->next;
} while (surf->key < surf2->key);
if (surf->key == surf2->key)
{
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (!surf->insubmodel)
goto continue_search;
// must be two bmodels in the same leaf; don't care which is really
// in front, because they'll never be farthest anyway
}
goto gotposition;
newtop:
// emit a span (obscures current top)
iu = edge->u >> 20;
if (iu > surf2->last_u)
{
span = span_p++;
span->u = surf2->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf2->spans;
surf2->spans = span;
}
// set last_u on the new span
surf->last_u = iu;
gotposition:
// insert before surf2
surf->next = surf2;
surf->prev = surf2->prev;
surf2->prev->next = surf;
surf2->prev = surf;
}
}
/*
==============
R_TrailingEdge
==============
*/
void R_TrailingEdge (surf_t *surf, edge_t *edge)
{
espan_t *span;
int iu;
// don't generate a span if this is an inverted span, with the end
// edge preceding the start edge (that is, we haven't seen the
// start edge yet)
if (--surf->spanstate == 0)
{
if (surf->insubmodel)
r_bmodelactive--;
if (surf == surfaces[1].next)
{
// emit a span (current top going away)
iu = edge->u >> 20;
if (iu > surf->last_u)
{
span = span_p++;
span->u = surf->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf->spans;
surf->spans = span;
}
// set last_u on the surface below
surf->next->last_u = iu;
}
surf->prev->next = surf->next;
surf->next->prev = surf->prev;
}
}
#if !id386
/*
==============
R_LeadingEdge
==============
*/
void R_LeadingEdge (edge_t *edge)
{
espan_t *span;
surf_t *surf, *surf2;
int iu;
double fu, newzi, testzi, newzitop, newzibottom;
if (edge->surfs[1])
{
// it's adding a new surface in, so find the correct place
surf = &surfaces[edge->surfs[1]];
// don't start a span if this is an inverted span, with the end
// edge preceding the start edge (that is, we've already seen the
// end edge)
if (++surf->spanstate == 1)
{
if (surf->insubmodel)
r_bmodelactive++;
surf2 = surfaces[1].next;
if (surf->key < surf2->key)
goto newtop;
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (surf->insubmodel && (surf->key == surf2->key))
{
// must be two bmodels in the same leaf; sort on 1/z
fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
newzi = surf->d_ziorigin + fv*surf->d_zistepv +
fu*surf->d_zistepu;
newzibottom = newzi * 0.99;
testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
fu*surf2->d_zistepu;
if (newzibottom >= testzi)
{
goto newtop;
}
newzitop = newzi * 1.01;
if (newzitop >= testzi)
{
if (surf->d_zistepu >= surf2->d_zistepu)
{
goto newtop;
}
}
}
continue_search:
do
{
surf2 = surf2->next;
} while (surf->key > surf2->key);
if (surf->key == surf2->key)
{
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (!surf->insubmodel)
goto continue_search;
// must be two bmodels in the same leaf; sort on 1/z
fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
newzi = surf->d_ziorigin + fv*surf->d_zistepv +
fu*surf->d_zistepu;
newzibottom = newzi * 0.99;
testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
fu*surf2->d_zistepu;
if (newzibottom >= testzi)
{
goto gotposition;
}
newzitop = newzi * 1.01;
if (newzitop >= testzi)
{
if (surf->d_zistepu >= surf2->d_zistepu)
{
goto gotposition;
}
}
goto continue_search;
}
goto gotposition;
newtop:
// emit a span (obscures current top)
iu = edge->u >> 20;
if (iu > surf2->last_u)
{
span = span_p++;
span->u = surf2->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf2->spans;
surf2->spans = span;
}
// set last_u on the new span
surf->last_u = iu;
gotposition:
// insert before surf2
surf->next = surf2;
surf->prev = surf2->prev;
surf2->prev->next = surf;
surf2->prev = surf;
}
}
}
/*
==============
R_GenerateSpans
==============
*/
void R_GenerateSpans (void)
{
edge_t *edge;
surf_t *surf;
r_bmodelactive = 0;
// clear active surfaces to just the background surface
surfaces[1].next = surfaces[1].prev = &surfaces[1];
surfaces[1].last_u = edge_head_u_shift20;
// generate spans
for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
{
if (edge->surfs[0])
{
// it has a left surface, so a surface is going away for this span
surf = &surfaces[edge->surfs[0]];
R_TrailingEdge (surf, edge);
if (!edge->surfs[1])
continue;
}
R_LeadingEdge (edge);
}
R_CleanupSpan ();
}
#endif // !id386
void R_LeadingTransEdge (edge_t *edge)
{
espan_t *span;
surf_t *surf, *surf2;
int iu;
double fu, newzi, testzi, newzitop, newzibottom;
if (edge->surfs[1])
{
// it's adding a new surface in, so find the correct place
surf = &surfaces[edge->surfs[1]];
// don't start a span if this is an inverted span, with the end
// edge preceding the start edge (that is, we've already seen the
// end edge)
if (++surf->spanstate == 1)
{
if (surf->insubmodel)
r_bmodelactive++;
surf2 = surfaces[1].next;
if (surf->key < surf2->key)
goto newtop;
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (surf->insubmodel && (surf->key == surf2->key))
{
// must be two bmodels in the same leaf; sort on 1/z
fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
newzi = surf->d_ziorigin + fv*surf->d_zistepv +
fu*surf->d_zistepu;
newzibottom = newzi * 0.99;
testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
fu*surf2->d_zistepu;
if (newzibottom >= testzi)
{
goto newtop;
}
newzitop = newzi * 1.01;
if (newzitop >= testzi)
{
if (surf->d_zistepu >= surf2->d_zistepu)
{
goto newtop;
}
}
}
continue_search:
do
{
surf2 = surf2->next;
} while (surf->key > surf2->key);
if (surf->key == surf2->key)
{
// if it's two surfaces on the same plane, the one that's already
// active is in front, so keep going unless it's a bmodel
if (!surf->insubmodel)
goto continue_search;
// must be two bmodels in the same leaf; sort on 1/z
fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
newzi = surf->d_ziorigin + fv*surf->d_zistepv +
fu*surf->d_zistepu;
newzibottom = newzi * 0.99;
testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
fu*surf2->d_zistepu;
if (newzibottom >= testzi)
{
goto gotposition;
}
newzitop = newzi * 1.01;
if (newzitop >= testzi)
{
if (surf->d_zistepu >= surf2->d_zistepu)
{
goto gotposition;
}
}
goto continue_search;
}
goto gotposition;
newtop:
// emit a span (obscures current top)
iu = edge->u >> 20;
if (iu > surf2->last_u)
{
span = span_p++;
span->u = surf2->last_u;
span->count = iu - span->u;
span->v = current_iv;
span->pnext = surf2->spans;
surf2->spans = span;
}
// set last_u on the new span
surf->last_u = iu;
gotposition:
// insert before surf2
surf->next = surf2;
surf->prev = surf2->prev;
surf2->prev->next = surf;
surf2->prev = surf;
}
}
}
void R_GenerateSpansTrans (void)
{
edge_t *edge;
surf_t *surf;
r_bmodelactive = 0;
// clear active surfaces to just the background surface
surfaces[1].next = surfaces[1].prev = &surfaces[1];
surfaces[1].last_u = edge_head_u_shift20;
// generate spans
for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
{
if (edge->surfs[0])
{
// it has a left surface, so a surface is going away for this span
surf = &surfaces[edge->surfs[0]];
R_TrailingEdge (surf, edge);
if (!edge->surfs[1])
continue;
}
R_LeadingTransEdge (edge);
}
R_CleanupSpan ();
}
/*
==============
R_GenerateSpansBackward
==============
*/
void R_GenerateSpansBackward (void)
{
edge_t *edge;
r_bmodelactive = 0;
// clear active surfaces to just the background surface
surfaces[1].next = surfaces[1].prev = &surfaces[1];
surfaces[1].last_u = edge_head_u_shift20;
// generate spans
for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
{
if (edge->surfs[0])
R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
if (edge->surfs[1])
R_LeadingEdgeBackwards (edge);
}
R_CleanupSpan ();
}
/*
==============
R_ScanEdges
Input:
newedges[] array
this has links to edges, which have links to surfaces
Output:
Each surface has a linked list of its visible spans
==============
*/
void R_ScanEdges (void)
{
int iv, bottom;
qbyte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
espan_t *basespan_p;
surf_t *s;
basespan_p = (espan_t *)
((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
span_p = basespan_p;
// clear active edges to just the background edges around the whole screen
// FIXME: most of this only needs to be set up once
edge_head.u = r_refdef.vrect.x << 20;
edge_head_u_shift20 = edge_head.u >> 20;
edge_head.u_step = 0;
edge_head.prev = NULL;
edge_head.next = &edge_tail;
edge_head.surfs[0] = 0;
edge_head.surfs[1] = 1;
edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
edge_tail_u_shift20 = edge_tail.u >> 20;
edge_tail.u_step = 0;
edge_tail.prev = &edge_head;
edge_tail.next = &edge_aftertail;
edge_tail.surfs[0] = 1;
edge_tail.surfs[1] = 0;
edge_aftertail.u = -1; // force a move
edge_aftertail.u_step = 0;
edge_aftertail.next = &edge_sentinel;
edge_aftertail.prev = &edge_tail;
// FIXME: do we need this now that we clamp x in r_draw.c?
edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this
edge_sentinel.prev = &edge_aftertail;
//
// process all scan lines
//
bottom = r_refdef.vrectbottom - 1;
for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
{
current_iv = iv;
fv = (float)iv;
// mark that the head (background start) span is pre-included
surfaces[1].spanstate = 1;
if (newedges[iv])
{
R_InsertNewEdges (newedges[iv], edge_head.next);
}
(*pdrawfunc) ();
// flush the span list if we can't be sure we have enough spans left for
// the next scan
if (span_p > max_span_p)
{
VID_UnlockBuffer ();
S_ExtraUpdate (); // don't let sound get messed up if going slow
VID_LockBuffer ();
if (r_drawculledpolys)
R_DrawCulledPolys ();
else
D_DrawSurfaces ();
// clear the surface span pointers
for (s = &surfaces[1] ; s<surface_p ; s++)
s->spans = NULL;
span_p = basespan_p;
}
if (removeedges[iv])
R_RemoveEdges (removeedges[iv]);
if (edge_head.next != &edge_tail)
R_StepActiveU (edge_head.next);
}
// do the last scan (no need to step or sort or remove on the last scan)
current_iv = iv;
fv = (float)iv;
// mark that the head (background start) span is pre-included
surfaces[1].spanstate = 1;
if (newedges[iv])
R_InsertNewEdges (newedges[iv], edge_head.next);
(*pdrawfunc) ();
// draw whatever's left in the span list
if (r_drawculledpolys)
R_DrawCulledPolys ();
else
D_DrawSurfaces ();
}

750
engine/sw/r_edgea.s Normal file
View file

@ -0,0 +1,750 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// r_edgea.s
// x86 assembly-language edge-processing code.
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#if id386
.data
Ltemp: .long 0
float_1_div_0100000h: .long 0x35800000 // 1.0/(float)0x100000
float_point_999: .single 0.999
float_1_point_001: .single 1.001
.text
//--------------------------------------------------------------------
#define edgestoadd 4+8 // note odd stack offsets because of interleaving
#define edgelist 8+12 // with pushes
.globl C(R_EdgeCodeStart)
C(R_EdgeCodeStart):
.globl C(R_InsertNewEdges)
C(R_InsertNewEdges):
pushl %edi
pushl %esi // preserve register variables
movl edgestoadd(%esp),%edx
pushl %ebx
movl edgelist(%esp),%ecx
LDoNextEdge:
movl et_u(%edx),%eax
movl %edx,%edi
LContinueSearch:
movl et_u(%ecx),%ebx
movl et_next(%ecx),%esi
cmpl %ebx,%eax
jle LAddedge
movl et_u(%esi),%ebx
movl et_next(%esi),%ecx
cmpl %ebx,%eax
jle LAddedge2
movl et_u(%ecx),%ebx
movl et_next(%ecx),%esi
cmpl %ebx,%eax
jle LAddedge
movl et_u(%esi),%ebx
movl et_next(%esi),%ecx
cmpl %ebx,%eax
jg LContinueSearch
LAddedge2:
movl et_next(%edx),%edx
movl et_prev(%esi),%ebx
movl %esi,et_next(%edi)
movl %ebx,et_prev(%edi)
movl %edi,et_next(%ebx)
movl %edi,et_prev(%esi)
movl %esi,%ecx
cmpl $0,%edx
jnz LDoNextEdge
jmp LDone
.align 4
LAddedge:
movl et_next(%edx),%edx
movl et_prev(%ecx),%ebx
movl %ecx,et_next(%edi)
movl %ebx,et_prev(%edi)
movl %edi,et_next(%ebx)
movl %edi,et_prev(%ecx)
cmpl $0,%edx
jnz LDoNextEdge
LDone:
popl %ebx // restore register variables
popl %esi
popl %edi
ret
//--------------------------------------------------------------------
#define predge 4+4
.globl C(R_RemoveEdges)
C(R_RemoveEdges):
pushl %ebx
movl predge(%esp),%eax
Lre_loop:
movl et_next(%eax),%ecx
movl et_nextremove(%eax),%ebx
movl et_prev(%eax),%edx
testl %ebx,%ebx
movl %edx,et_prev(%ecx)
jz Lre_done
movl %ecx,et_next(%edx)
movl et_next(%ebx),%ecx
movl et_prev(%ebx),%edx
movl et_nextremove(%ebx),%eax
movl %edx,et_prev(%ecx)
testl %eax,%eax
movl %ecx,et_next(%edx)
jnz Lre_loop
popl %ebx
ret
Lre_done:
movl %ecx,et_next(%edx)
popl %ebx
ret
//--------------------------------------------------------------------
#define pedgelist 4+4 // note odd stack offset because of interleaving
// with pushes
.globl C(R_StepActiveU)
C(R_StepActiveU):
pushl %edi
movl pedgelist(%esp),%edx
pushl %esi // preserve register variables
pushl %ebx
movl et_prev(%edx),%esi
LNewEdge:
movl et_u(%esi),%edi
LNextEdge:
movl et_u(%edx),%eax
movl et_u_step(%edx),%ebx
addl %ebx,%eax
movl et_next(%edx),%esi
movl %eax,et_u(%edx)
cmpl %edi,%eax
jl LPushBack
movl et_u(%esi),%edi
movl et_u_step(%esi),%ebx
addl %ebx,%edi
movl et_next(%esi),%edx
movl %edi,et_u(%esi)
cmpl %eax,%edi
jl LPushBack2
movl et_u(%edx),%eax
movl et_u_step(%edx),%ebx
addl %ebx,%eax
movl et_next(%edx),%esi
movl %eax,et_u(%edx)
cmpl %edi,%eax
jl LPushBack
movl et_u(%esi),%edi
movl et_u_step(%esi),%ebx
addl %ebx,%edi
movl et_next(%esi),%edx
movl %edi,et_u(%esi)
cmpl %eax,%edi
jnl LNextEdge
LPushBack2:
movl %edx,%ebx
movl %edi,%eax
movl %esi,%edx
movl %ebx,%esi
LPushBack:
// push it back to keep it sorted
movl et_prev(%edx),%ecx
movl et_next(%edx),%ebx
// done if the -1 in edge_aftertail triggered this
cmpl $(C(edge_aftertail)),%edx
jz LUDone
// pull the edge out of the edge list
movl et_prev(%ecx),%edi
movl %ecx,et_prev(%esi)
movl %ebx,et_next(%ecx)
// find out where the edge goes in the edge list
LPushBackLoop:
movl et_prev(%edi),%ecx
movl et_u(%edi),%ebx
cmpl %ebx,%eax
jnl LPushBackFound
movl et_prev(%ecx),%edi
movl et_u(%ecx),%ebx
cmpl %ebx,%eax
jl LPushBackLoop
movl %ecx,%edi
// put the edge back into the edge list
LPushBackFound:
movl et_next(%edi),%ebx
movl %edi,et_prev(%edx)
movl %ebx,et_next(%edx)
movl %edx,et_next(%edi)
movl %edx,et_prev(%ebx)
movl %esi,%edx
movl et_prev(%esi),%esi
cmpl $(C(edge_tail)),%edx
jnz LNewEdge
LUDone:
popl %ebx // restore register variables
popl %esi
popl %edi
ret
//--------------------------------------------------------------------
#define surf 4 // note this is loaded before any pushes
.align 4
TrailingEdge:
movl st_spanstate(%esi),%eax // check for edge inversion
decl %eax
jnz LInverted
movl %eax,st_spanstate(%esi)
movl st_insubmodel(%esi),%ecx
movl 0x12345678,%edx // surfaces[1].st_next
LPatch0:
movl C(r_bmodelactive),%eax
subl %ecx,%eax
cmpl %esi,%edx
movl %eax,C(r_bmodelactive)
jnz LNoEmit // surface isn't on top, just remove
// emit a span (current top going away)
movl et_u(%ebx),%eax
shrl $20,%eax // iu = integral pixel u
movl st_last_u(%esi),%edx
movl st_next(%esi),%ecx
cmpl %edx,%eax
jle LNoEmit2 // iu <= surf->last_u, so nothing to emit
movl %eax,st_last_u(%ecx) // surf->next->last_u = iu;
subl %edx,%eax
movl %edx,espan_t_u(%ebp) // span->u = surf->last_u;
movl %eax,espan_t_count(%ebp) // span->count = iu - span->u;
movl C(current_iv),%eax
movl %eax,espan_t_v(%ebp) // span->v = current_iv;
movl st_spans(%esi),%eax
movl %eax,espan_t_pnext(%ebp) // span->pnext = surf->spans;
movl %ebp,st_spans(%esi) // surf->spans = span;
addl $(espan_t_size),%ebp
movl st_next(%esi),%edx // remove the surface from the surface
movl st_prev(%esi),%esi // stack
movl %edx,st_next(%esi)
movl %esi,st_prev(%edx)
ret
LNoEmit2:
movl %eax,st_last_u(%ecx) // surf->next->last_u = iu;
movl st_next(%esi),%edx // remove the surface from the surface
movl st_prev(%esi),%esi // stack
movl %edx,st_next(%esi)
movl %esi,st_prev(%edx)
ret
LNoEmit:
movl st_next(%esi),%edx // remove the surface from the surface
movl st_prev(%esi),%esi // stack
movl %edx,st_next(%esi)
movl %esi,st_prev(%edx)
ret
LInverted:
movl %eax,st_spanstate(%esi)
ret
//--------------------------------------------------------------------
// trailing edge only
Lgs_trailing:
pushl $Lgs_nextedge
jmp TrailingEdge
.globl C(R_GenerateSpans)
C(R_GenerateSpans):
pushl %ebp // preserve caller's stack frame
pushl %edi
pushl %esi // preserve register variables
pushl %ebx
// clear active surfaces to just the background surface
movl C(surfaces),%eax
movl C(edge_head_u_shift20),%edx
addl $(st_size),%eax
// %ebp = span_p throughout
movl C(span_p),%ebp
movl $0,C(r_bmodelactive)
movl %eax,st_next(%eax)
movl %eax,st_prev(%eax)
movl %edx,st_last_u(%eax)
movl C(edge_head)+et_next,%ebx // edge=edge_head.next
// generate spans
cmpl $(C(edge_tail)),%ebx // done if empty list
jz Lgs_lastspan
Lgs_edgeloop:
movl et_surfs(%ebx),%edi
movl C(surfaces),%eax
movl %edi,%esi
andl $0xFFFF0000,%edi
andl $0xFFFF,%esi
jz Lgs_leading // not a trailing edge
// it has a left surface, so a surface is going away for this span
shll $(SURF_T_SHIFT),%esi
addl %eax,%esi
testl %edi,%edi
jz Lgs_trailing
// both leading and trailing
call TrailingEdge
movl C(surfaces),%eax
// ---------------------------------------------------------------
// handle a leading edge
// ---------------------------------------------------------------
Lgs_leading:
shrl $16-SURF_T_SHIFT,%edi
movl C(surfaces),%eax
addl %eax,%edi
movl 0x12345678,%esi // surf2 = surfaces[1].next;
LPatch2:
movl st_spanstate(%edi),%edx
movl st_insubmodel(%edi),%eax
testl %eax,%eax
jnz Lbmodel_leading
// handle a leading non-bmodel edge
// don't start a span if this is an inverted span, with the end edge preceding
// the start edge (that is, we've already seen the end edge)
testl %edx,%edx
jnz Lxl_done
// if (surf->key < surf2->key)
// goto newtop;
incl %edx
movl st_key(%edi),%eax
movl %edx,st_spanstate(%edi)
movl st_key(%esi),%ecx
cmpl %ecx,%eax
jl Lnewtop
// main sorting loop to search through surface stack until insertion point
// found. Always terminates because background surface is sentinel
// do
// {
// surf2 = surf2->next;
// } while (surf->key >= surf2->key);
Lsortloopnb:
movl st_next(%esi),%esi
movl st_key(%esi),%ecx
cmpl %ecx,%eax
jge Lsortloopnb
jmp LInsertAndExit
// handle a leading bmodel edge
.align 4
Lbmodel_leading:
// don't start a span if this is an inverted span, with the end edge preceding
// the start edge (that is, we've already seen the end edge)
testl %edx,%edx
jnz Lxl_done
movl C(r_bmodelactive),%ecx
incl %edx
incl %ecx
movl %edx,st_spanstate(%edi)
movl %ecx,C(r_bmodelactive)
// if (surf->key < surf2->key)
// goto newtop;
movl st_key(%edi),%eax
movl st_key(%esi),%ecx
cmpl %ecx,%eax
jl Lnewtop
// if ((surf->key == surf2->key) && surf->insubmodel)
// {
jz Lzcheck_for_newtop
// main sorting loop to search through surface stack until insertion point
// found. Always terminates because background surface is sentinel
// do
// {
// surf2 = surf2->next;
// } while (surf->key > surf2->key);
Lsortloop:
movl st_next(%esi),%esi
movl st_key(%esi),%ecx
cmpl %ecx,%eax
jg Lsortloop
jne LInsertAndExit
// Do 1/z sorting to see if we've arrived in the right position
movl et_u(%ebx),%eax
subl $0xFFFFF,%eax
movl %eax,Ltemp
fildl Ltemp
fmuls float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) *
// (1.0 / 0x100000);
fld %st(0) // fu | fu
fmuls st_d_zistepu(%edi) // fu*surf->d_zistepu | fu
flds C(fv) // fv | fu*surf->d_zistepu | fu
fmuls st_d_zistepv(%edi) // fv*surf->d_zistepv | fu*surf->d_zistepu | fu
fxch %st(1) // fu*surf->d_zistepu | fv*surf->d_zistepv | fu
fadds st_d_ziorigin(%edi) // fu*surf->d_zistepu + surf->d_ziorigin |
// fv*surf->d_zistepv | fu
flds st_d_zistepu(%esi) // surf2->d_zistepu |
// fu*surf->d_zistepu + surf->d_ziorigin |
// fv*surf->d_zistepv | fu
fmul %st(3),%st(0) // fu*surf2->d_zistepu |
// fu*surf->d_zistepu + surf->d_ziorigin |
// fv*surf->d_zistepv | fu
fxch %st(1) // fu*surf->d_zistepu + surf->d_ziorigin |
// fu*surf2->d_zistepu |
// fv*surf->d_zistepv | fu
faddp %st(0),%st(2) // fu*surf2->d_zistepu | newzi | fu
flds C(fv) // fv | fu*surf2->d_zistepu | newzi | fu
fmuls st_d_zistepv(%esi) // fv*surf2->d_zistepv |
// fu*surf2->d_zistepu | newzi | fu
fld %st(2) // newzi | fv*surf2->d_zistepv |
// fu*surf2->d_zistepu | newzi | fu
fmuls float_point_999 // newzibottom | fv*surf2->d_zistepv |
// fu*surf2->d_zistepu | newzi | fu
fxch %st(2) // fu*surf2->d_zistepu | fv*surf2->d_zistepv |
// newzibottom | newzi | fu
fadds st_d_ziorigin(%esi) // fu*surf2->d_zistepu + surf2->d_ziorigin |
// fv*surf2->d_zistepv | newzibottom | newzi |
// fu
faddp %st(0),%st(1) // testzi | newzibottom | newzi | fu
fxch %st(1) // newzibottom | testzi | newzi | fu
// if (newzibottom >= testzi)
// goto Lgotposition;
fcomp %st(1) // testzi | newzi | fu
fxch %st(1) // newzi | testzi | fu
fmuls float_1_point_001 // newzitop | testzi | fu
fxch %st(1) // testzi | newzitop | fu
fnstsw %ax
testb $0x01,%ah
jz Lgotposition_fpop3
// if (newzitop >= testzi)
// {
fcomp %st(1) // newzitop | fu
fnstsw %ax
testb $0x45,%ah
jz Lsortloop_fpop2
// if (surf->d_zistepu >= surf2->d_zistepu)
// goto newtop;
flds st_d_zistepu(%edi) // surf->d_zistepu | newzitop| fu
fcomps st_d_zistepu(%esi) // newzitop | fu
fnstsw %ax
testb $0x01,%ah
jz Lgotposition_fpop2
fstp %st(0) // clear the FPstack
fstp %st(0)
movl st_key(%edi),%eax
jmp Lsortloop
Lgotposition_fpop3:
fstp %st(0)
Lgotposition_fpop2:
fstp %st(0)
fstp %st(0)
jmp LInsertAndExit
// emit a span (obscures current top)
Lnewtop_fpop3:
fstp %st(0)
Lnewtop_fpop2:
fstp %st(0)
fstp %st(0)
movl st_key(%edi),%eax // reload the sorting key
Lnewtop:
movl et_u(%ebx),%eax
movl st_last_u(%esi),%edx
shrl $20,%eax // iu = integral pixel u
movl %eax,st_last_u(%edi) // surf->last_u = iu;
cmpl %edx,%eax
jle LInsertAndExit // iu <= surf->last_u, so nothing to emit
subl %edx,%eax
movl %edx,espan_t_u(%ebp) // span->u = surf->last_u;
movl %eax,espan_t_count(%ebp) // span->count = iu - span->u;
movl C(current_iv),%eax
movl %eax,espan_t_v(%ebp) // span->v = current_iv;
movl st_spans(%esi),%eax
movl %eax,espan_t_pnext(%ebp) // span->pnext = surf->spans;
movl %ebp,st_spans(%esi) // surf->spans = span;
addl $(espan_t_size),%ebp
LInsertAndExit:
// insert before surf2
movl %esi,st_next(%edi) // surf->next = surf2;
movl st_prev(%esi),%eax
movl %eax,st_prev(%edi) // surf->prev = surf2->prev;
movl %edi,st_prev(%esi) // surf2->prev = surf;
movl %edi,st_next(%eax) // surf2->prev->next = surf;
// ---------------------------------------------------------------
// leading edge done
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// see if there are any more edges
// ---------------------------------------------------------------
Lgs_nextedge:
movl et_next(%ebx),%ebx
cmpl $(C(edge_tail)),%ebx
jnz Lgs_edgeloop
// clean up at the right edge
Lgs_lastspan:
// now that we've reached the right edge of the screen, we're done with any
// unfinished surfaces, so emit a span for whatever's on top
movl 0x12345678,%esi // surfaces[1].st_next
LPatch3:
movl C(edge_tail_u_shift20),%eax
xorl %ecx,%ecx
movl st_last_u(%esi),%edx
subl %edx,%eax
jle Lgs_resetspanstate
movl %edx,espan_t_u(%ebp)
movl %eax,espan_t_count(%ebp)
movl C(current_iv),%eax
movl %eax,espan_t_v(%ebp)
movl st_spans(%esi),%eax
movl %eax,espan_t_pnext(%ebp)
movl %ebp,st_spans(%esi)
addl $(espan_t_size),%ebp
// reset spanstate for all surfaces in the surface stack
Lgs_resetspanstate:
movl %ecx,st_spanstate(%esi)
movl st_next(%esi),%esi
cmpl $0x12345678,%esi // &surfaces[1]
LPatch4:
jnz Lgs_resetspanstate
// store the final span_p
movl %ebp,C(span_p)
popl %ebx // restore register variables
popl %esi
popl %edi
popl %ebp // restore the caller's stack frame
ret
// ---------------------------------------------------------------
// 1/z sorting for bmodels in the same leaf
// ---------------------------------------------------------------
.align 4
Lxl_done:
incl %edx
movl %edx,st_spanstate(%edi)
jmp Lgs_nextedge
.align 4
Lzcheck_for_newtop:
movl et_u(%ebx),%eax
subl $0xFFFFF,%eax
movl %eax,Ltemp
fildl Ltemp
fmuls float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) *
// (1.0 / 0x100000);
fld %st(0) // fu | fu
fmuls st_d_zistepu(%edi) // fu*surf->d_zistepu | fu
flds C(fv) // fv | fu*surf->d_zistepu | fu
fmuls st_d_zistepv(%edi) // fv*surf->d_zistepv | fu*surf->d_zistepu | fu
fxch %st(1) // fu*surf->d_zistepu | fv*surf->d_zistepv | fu
fadds st_d_ziorigin(%edi) // fu*surf->d_zistepu + surf->d_ziorigin |
// fv*surf->d_zistepv | fu
flds st_d_zistepu(%esi) // surf2->d_zistepu |
// fu*surf->d_zistepu + surf->d_ziorigin |
// fv*surf->d_zistepv | fu
fmul %st(3),%st(0) // fu*surf2->d_zistepu |
// fu*surf->d_zistepu + surf->d_ziorigin |
// fv*surf->d_zistepv | fu
fxch %st(1) // fu*surf->d_zistepu + surf->d_ziorigin |
// fu*surf2->d_zistepu |
// fv*surf->d_zistepv | fu
faddp %st(0),%st(2) // fu*surf2->d_zistepu | newzi | fu
flds C(fv) // fv | fu*surf2->d_zistepu | newzi | fu
fmuls st_d_zistepv(%esi) // fv*surf2->d_zistepv |
// fu*surf2->d_zistepu | newzi | fu
fld %st(2) // newzi | fv*surf2->d_zistepv |
// fu*surf2->d_zistepu | newzi | fu
fmuls float_point_999 // newzibottom | fv*surf2->d_zistepv |
// fu*surf2->d_zistepu | newzi | fu
fxch %st(2) // fu*surf2->d_zistepu | fv*surf2->d_zistepv |
// newzibottom | newzi | fu
fadds st_d_ziorigin(%esi) // fu*surf2->d_zistepu + surf2->d_ziorigin |
// fv*surf2->d_zistepv | newzibottom | newzi |
// fu
faddp %st(0),%st(1) // testzi | newzibottom | newzi | fu
fxch %st(1) // newzibottom | testzi | newzi | fu
// if (newzibottom >= testzi)
// goto newtop;
fcomp %st(1) // testzi | newzi | fu
fxch %st(1) // newzi | testzi | fu
fmuls float_1_point_001 // newzitop | testzi | fu
fxch %st(1) // testzi | newzitop | fu
fnstsw %ax
testb $0x01,%ah
jz Lnewtop_fpop3
// if (newzitop >= testzi)
// {
fcomp %st(1) // newzitop | fu
fnstsw %ax
testb $0x45,%ah
jz Lsortloop_fpop2
// if (surf->d_zistepu >= surf2->d_zistepu)
// goto newtop;
flds st_d_zistepu(%edi) // surf->d_zistepu | newzitop | fu
fcomps st_d_zistepu(%esi) // newzitop | fu
fnstsw %ax
testb $0x01,%ah
jz Lnewtop_fpop2
Lsortloop_fpop2:
fstp %st(0) // clear the FP stack
fstp %st(0)
movl st_key(%edi),%eax
jmp Lsortloop
.globl C(R_EdgeCodeEnd)
C(R_EdgeCodeEnd):
//----------------------------------------------------------------------
// Surface array address code patching routine
//----------------------------------------------------------------------
.align 4
.globl C(R_SurfacePatch)
C(R_SurfacePatch):
movl C(surfaces),%eax
addl $(st_size),%eax
movl %eax,LPatch4-4
addl $(st_next),%eax
movl %eax,LPatch0-4
movl %eax,LPatch2-4
movl %eax,LPatch3-4
ret
#endif // id386

462
engine/sw/r_light.c Normal file
View file

@ -0,0 +1,462 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_light.c
#include "quakedef.h"
#include "r_local.h"
int r_dlightframecount;
/*
==================
R_AnimateLight
==================
*/
void SWR_AnimateLight (void)
{
int i,j,k;
//
// light animations
// 'm' is normal light, 'a' is no light, 'z' is double bright
i = (int)(cl.time*10);
for (j=0 ; j<MAX_LIGHTSTYLES ; j++)
{
if (!cl_lightstyle[j].length)
{
d_lightstylevalue[j] = 256;
continue;
}
k = i % cl_lightstyle[j].length;
k = cl_lightstyle[j].map[k] - 'a';
k = k*22;
d_lightstylevalue[j] = k;
}
}
/*
=============================================================================
DYNAMIC LIGHTS
=============================================================================
*/
/*
=============
R_MarkLights
=============
*/
void SWR_MarkLights (dlight_t *light, int bit, mnode_t *node)
{
mplane_t *splitplane;
float dist;
msurface_t *surf;
int i;
if (node->contents < 0)
return;
splitplane = node->plane;
dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
if (dist > light->radius)
{
SWR_MarkLights (light, bit, node->children[0]);
return;
}
if (dist < -light->radius)
{
SWR_MarkLights (light, bit, node->children[1]);
return;
}
// mark the polygons
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
if (surf->dlightframe != r_dlightframecount)
{
surf->dlightbits = 0;
surf->dlightframe = r_dlightframecount;
}
surf->dlightbits |= bit;
}
SWR_MarkLights (light, bit, node->children[0]);
SWR_MarkLights (light, bit, node->children[1]);
}
void SWR_Q2MarkLights (dlight_t *light, int bit, mnode_t *node)
{
mplane_t *splitplane;
float dist;
msurface_t *surf;
int i;
if (node->contents != -1)
return;
splitplane = node->plane;
dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
if (dist > light->radius)
{
SWR_Q2MarkLights (light, bit, node->children[0]);
return;
}
if (dist < -light->radius)
{
SWR_Q2MarkLights (light, bit, node->children[1]);
return;
}
// mark the polygons
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
if (surf->dlightframe != r_dlightframecount)
{
surf->dlightbits = 0;
surf->dlightframe = r_dlightframecount;
}
surf->dlightbits |= bit;
}
SWR_Q2MarkLights (light, bit, node->children[0]);
SWR_Q2MarkLights (light, bit, node->children[1]);
}
/*
=============
R_PushDlights
=============
*/
void SWR_PushDlights (void)
{
int i;
dlight_t *l;
r_dlightframecount = r_framecount + 1; // because the count hasn't
// advanced yet for this frame
if (!r_dynamic.value)
return;
l = cl_dlights;
if (cl.worldmodel->fromgame == fg_quake2)
{
for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
{
if (l->die < cl.time || !l->radius)
continue;
SWR_Q2MarkLights ( l, 1<<i, cl.worldmodel->nodes );
}
}
else
{
for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
{
if (l->die < cl.time || !l->radius)
continue;
SWR_MarkLights ( l, 1<<i, cl.worldmodel->nodes );
}
}
}
/*
=============================================================================
LIGHT SAMPLING
=============================================================================
*/
int SWRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
{
int r;
float front, back, frac;
int side;
mplane_t *plane;
vec3_t mid;
msurface_t *surf;
int s, t, ds, dt;
int i;
mtexinfo_t *tex;
qbyte *lightmap;
unsigned scale;
int maps;
if (cl.worldmodel->fromgame == fg_quake2)
{
if (node->contents != -1)
return -1; // solid
}
else if (node->contents < 0)
return -1; // didn't hit anything
// calculate mid point
// FIXME: optimize for axial
plane = node->plane;
front = DotProduct (start, plane->normal) - plane->dist;
back = DotProduct (end, plane->normal) - plane->dist;
side = front < 0;
if ( (back < 0) == side)
return SWRecursiveLightPoint (node->children[side], start, end);
frac = front / (front-back);
mid[0] = start[0] + (end[0] - start[0])*frac;
mid[1] = start[1] + (end[1] - start[1])*frac;
mid[2] = start[2] + (end[2] - start[2])*frac;
// go down front side
r = SWRecursiveLightPoint (node->children[side], start, mid);
if (r >= 0)
return r; // hit something
if ( (back < 0) == side )
return -1; // didn't hit anuthing
// check for impact on this node
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
if (surf->flags & SURF_DRAWTILED)
continue; // no lightmaps
tex = surf->texinfo;
s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];;
if (s < surf->texturemins[0] ||
t < surf->texturemins[1])
continue;
ds = s - surf->texturemins[0];
dt = t - surf->texturemins[1];
if ( ds > surf->extents[0] || dt > surf->extents[1] )
continue;
if (!surf->samples)
return 0;
ds >>= 4;
dt >>= 4;
lightmap = surf->samples;
r = 0;
if (lightmap)
{
lightmap += (dt * ((surf->extents[0]>>4)+1) + ds);
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
maps++)
{
scale = d_lightstylevalue[surf->styles[maps]];
r += *lightmap * scale;
lightmap += ((surf->extents[0]>>4)+1) *
((surf->extents[1]>>4)+1);
}
r >>= 8;
}
return r;
}
// go down back side
return SWRecursiveLightPoint (node->children[!side], mid, end);
}
int SWRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end)
{
int r;
float front, back, frac;
int side;
mplane_t *plane;
vec3_t mid;
msurface_t *surf;
int s, t, ds, dt;
int i;
mtexinfo_t *tex;
qbyte *lightmap;
unsigned scale;
int maps;
if (cl.worldmodel->fromgame == fg_quake2)
{
if (node->contents != -1)
return -1; // solid
}
else if (node->contents < 0)
return -1; // didn't hit anything
// calculate mid point
// FIXME: optimize for axial
plane = node->plane;
front = DotProduct (start, plane->normal) - plane->dist;
back = DotProduct (end, plane->normal) - plane->dist;
side = front < 0;
if ( (back < 0) == side)
return SWRecursiveLightPoint3C (node->children[side], start, end);
frac = front / (front-back);
mid[0] = start[0] + (end[0] - start[0])*frac;
mid[1] = start[1] + (end[1] - start[1])*frac;
mid[2] = start[2] + (end[2] - start[2])*frac;
// go down front side
r = SWRecursiveLightPoint (node->children[side], start, mid);
if (r >= 0)
return r; // hit something
if ( (back < 0) == side )
return -1; // didn't hit anuthing
// check for impact on this node
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
if (surf->flags & SURF_DRAWTILED)
continue; // no lightmaps
tex = surf->texinfo;
s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];;
if (s < surf->texturemins[0] ||
t < surf->texturemins[1])
continue;
ds = s - surf->texturemins[0];
dt = t - surf->texturemins[1];
if ( ds > surf->extents[0] || dt > surf->extents[1] )
continue;
if (!surf->samples)
return 0;
ds >>= 4;
dt >>= 4;
lightmap = surf->samples;
r = 0;
if (lightmap)
{
lightmap += (dt * ((surf->extents[0]>>4)+1) + ds)*3;
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
maps++)
{
scale = d_lightstylevalue[surf->styles[maps]];
r += (lightmap[0]+lightmap[1]+lightmap[2])/3 * scale;
lightmap += ((surf->extents[0]>>4)+1) *
((surf->extents[1]>>4)+1)*3;
}
r >>= 8;
}
return r;
}
// go down back side
return SWRecursiveLightPoint3C (node->children[!side], mid, end);
}
int SWR_LightPoint (vec3_t p)
{
vec3_t end;
int r;
extern qboolean r_usinglits;
if (r_refdef.flags & 1 || !cl.worldmodel || !cl.worldmodel->lightdata)
return 255;
end[0] = p[0];
end[1] = p[1];
end[2] = p[2] - 2048;
if (r_usinglits)
r = SWRecursiveLightPoint3C (cl.worldmodel->nodes, p, end);
else
r = SWRecursiveLightPoint (cl.worldmodel->nodes, p, end);
if (r == -1)
r = 0;
if (r < r_refdef.ambientlight)
r = r_refdef.ambientlight;
return r;
}
void SWQ1BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir)
{
vec3_t end;
float r;
res_dir[0] = 0; //software doesn't load luxes
res_dir[1] = 1;
res_dir[2] = 1;
end[0] = point[0];
end[1] = point[1];
end[2] = point[2] - 2048;
r = SWRecursiveLightPoint3C(cl.worldmodel->nodes, point, end);
if (r < 0)
{
res_diffuse[0] = 0;
res_diffuse[1] = 0;
res_diffuse[2] = 0;
res_ambient[0] = 0;
res_ambient[1] = 0;
res_ambient[2] = 0;
}
else
{
res_diffuse[0] = r;
res_diffuse[1] = r;
res_diffuse[2] = r;
res_ambient[0] = r;
res_ambient[1] = r;
res_ambient[2] = r;
}
}

323
engine/sw/r_local.h Normal file
View file

@ -0,0 +1,323 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_local.h -- private refresh defs
#ifdef SWQUAKE
#include "r_shared.h"
#define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0)
// normalizing factor so player model works out to about
// 1 pixel per triangle
#define BMODEL_FULLY_CLIPPED 0x10 // value returned by R_BmodelCheckBBox ()
// if bbox is trivially rejected
//===========================================================================
// viewmodel lighting
typedef struct {
int ambientlight;
int shadelight;
float *plightvec;
} alight_t;
//===========================================================================
// clipped bmodel edges
typedef struct bedge_s
{
mvertex_t *v[2];
struct bedge_s *pnext;
} bedge_t;
typedef struct {
float fv[3]; // viewspace x, y
} auxvert_t;
//===========================================================================
extern cvar_t r_draworder;
extern cvar_t r_speeds;
extern cvar_t r_timegraph;
extern cvar_t r_graphheight;
extern cvar_t r_clearcolor;
extern cvar_t r_waterwarp;
extern cvar_t r_fullbright;
extern cvar_t r_drawentities;
extern cvar_t r_aliasstats;
extern cvar_t r_dspeeds;
extern cvar_t r_drawflat;
extern cvar_t r_ambient;
extern cvar_t r_reportsurfout;
extern cvar_t r_maxsurfs;
extern cvar_t r_numsurfs;
extern cvar_t r_reportedgeout;
extern cvar_t r_maxedges;
extern cvar_t r_numedges;
#define XCENTERING (1.0 / 2.0)
#define YCENTERING (1.0 / 2.0)
#define CLIP_EPSILON 0.001
#define BACKFACE_EPSILON 0.01
//===========================================================================
#define DIST_NOT_SET 98765
// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct clipplane_s
{
vec3_t normal;
float dist;
struct clipplane_s *next;
qbyte leftedge;
qbyte rightedge;
qbyte reserved[2];
} clipplane_t;
extern clipplane_t view_clipplanes[4];
//=============================================================================
void R_RenderWorld (void);
//=============================================================================
extern mplane_t screenedge[4];
extern vec3_t r_origin;
extern vec3_t r_entorigin;
extern float screenAspect;
extern float verticalFieldOfView;
extern float xOrigin, yOrigin;
extern int r_visframecount;
//=============================================================================
extern int vstartscan;
void R_ClearPolyList (void);
void R_DrawPolyList (void);
//
// current entity info
//
extern qboolean insubmodel;
extern vec3_t r_worldmodelorg;
void R_DrawSprite (void);
void R_RenderFace (msurface_t *fa, int clipflags);
void R_RenderPoly (msurface_t *fa, int clipflags);
void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf);
void R_TransformPlane (mplane_t *p, float *normal, float *dist);
void R_TransformFrustum (void);
void R_SetSkyFrame (void);
void R_DrawSurfaceBlock16From8 (void);
void R_DrawSurfaceBlock8 (void);
texture_t *SWR_TextureAnimation (texture_t *base);
#if id386
void R_DrawSurfaceBlock8_mip0 (void);
void R_DrawSurfaceBlock8_mip1 (void);
void R_DrawSurfaceBlock8_mip2 (void);
void R_DrawSurfaceBlock8_mip3 (void);
#endif
void R_GenSkyTile (void *pdest);
void R_GenSkyTile16 (void *pdest);
void R_Surf8Patch (void);
void R_Surf16Patch (void);
void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags);
void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel);
void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel);
surf_t *R_GetSurf (void);
void R_AliasDrawModel (alight_t *plighting);
void R_BeginEdgeFrame (void);
void R_ScanEdges (void);
void D_DrawSurfaces (void);
void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist);
void R_StepActiveU (edge_t *pedge);
void R_RemoveEdges (edge_t *pedge);
extern void R_Surf8Start (void);
extern void R_Surf8End (void);
extern void R_Surf16Start (void);
extern void R_Surf16End (void);
extern void R_EdgeCodeStart (void);
extern void R_EdgeCodeEnd (void);
extern void R_RotateBmodel (void);
extern int c_faceclip;
extern int r_polycount;
extern int r_wholepolycount;
extern model_t *cl_worldmodel;
extern int *pfrustum_indexes[4];
// !!! if this is changed, it must be changed in asm_draw.h too !!!
#define NEAR_CLIP 0.01
extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
extern int vstartscan;
extern fixed16_t sadjust, tadjust;
extern fixed16_t bbextents, bbextentt;
#define MAXBVERTINDEXES 1000 // new clipped vertices when clipping bmodels
// to the world BSP
extern mvertex_t *r_ptverts, *r_ptvertsmax;
extern vec3_t sbaseaxis[3], tbaseaxis[3];
extern float entity_rotation[3][3];
extern int reinit_surfcache;
extern int r_currentkey;
extern int r_currentbkey;
typedef struct btofpoly_s {
int clipflags;
msurface_t *psurf;
} btofpoly_t;
#define MAX_BTOFPOLYS 5000 // FIXME: tune this
extern int numbtofpolys;
extern btofpoly_t *pbtofpolys;
void R_InitTurb (void);
void R_ZDrawSubmodelPolys (model_t *clmodel);
//=========================================================
// Alias models
//=========================================================
extern int numverts;
extern int a_skinwidth;
extern mtriangle_t *ptriangles;
extern int numtriangles;
extern aliashdr_t *paliashdr;
extern mmdl_t *pmdl;
extern float leftclip, topclip, rightclip, bottomclip;
extern int r_acliptype;
extern finalvert_t *pfinalverts;
extern auxvert_t *pauxverts;
qboolean R_AliasCheckBBox (void);
//=========================================================
// turbulence stuff
#define AMP 8*0x10000
#define AMP2 3
#define SPEED 20
//=========================================================
// particle stuff
void R_DrawParticles (void);
void R_InitParticles (void);
void R_EmitSkyEffectTris(model_t *mod, msurface_t *fa);
void R_ClearParticles (void);
void R_ReadPointFile_f (void);
void R_SurfacePatch (void);
extern int r_amodels_drawn;
extern edge_t *auxedges;
extern int r_numallocatededges;
extern edge_t *r_edges, *edge_p, *edge_max;
extern edge_t *newedges[MAXHEIGHT];
extern edge_t *removeedges[MAXHEIGHT];
extern int screenwidth;
extern qboolean r_usinglits;
// FIXME: make stack vars when debugging done
extern edge_t edge_head;
extern edge_t edge_tail;
extern edge_t edge_aftertail;
extern int r_bmodelactive;
extern float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
extern float r_aliastransition, r_resfudge;
extern int r_outofsurfaces;
extern int r_outofedges;
extern mvertex_t *r_pcurrentvertbase;
extern int r_maxvalidedgeoffset;
void R_AliasClipTriangle (mtriangle_t *ptri);
extern float r_time1;
extern float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
extern float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
extern int r_frustum_indexes[4*6];
extern int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
extern qboolean r_surfsonstack;
extern cshift_t cshift_water;
extern qboolean r_dowarpold, r_viewchanged;
extern mleaf_t *r_viewleaf, *r_oldviewleaf;
extern vec3_t r_emins, r_emaxs;
extern mnode_t *r_pefragtopnode;
extern int r_clipflags;
extern int r_dlightframecount;
extern qboolean r_fov_greater_than_90;
void R_StoreEfrags (efrag_t **ppefrag);
void SWR_TimeRefresh_f (void);
void R_TimeGraph (void);
void R_PrintAliasStats (void);
void R_PrintTimes (void);
void R_PrintDSpeeds (void);
void SWR_AnimateLight (void);
int SWR_LightPoint (vec3_t p);
//void R_SetupFrame (void);
void R_cshift_f (void);
void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1);
void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip);
void R_Q1BSP_SplitEntityOnNode2 (mnode_t *node);
void SWR_MarkLights (dlight_t *light, int bit, mnode_t *node);
void SWR_DrawAlphaSurfaces( void );
void SWR_SetupFrame (void);
void R_InitSkyBox (void);
void R_InitSkyBox (void);
void SWR_BuildLightmaps(void);
void SWR_NetGraph (void);
#endif //def SWQUAKE

1816
engine/sw/r_main.c Normal file

File diff suppressed because it is too large Load diff

639
engine/sw/r_misc.c Normal file
View file

@ -0,0 +1,639 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_misc.c
#include "quakedef.h"
#include "r_local.h"
extern int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
/*
===============
R_CheckVariables
===============
*/
void R_CheckVariables (void)
{
}
/*
============
Show
Debugging use
============
*/
void Show (void)
{
vrect_t vr;
vr.x = vr.y = 0;
vr.width = vid.width;
vr.height = vid.height;
vr.pnext = NULL;
SWVID_Update (&vr);
}
/*
====================
R_TimeRefresh_f
For program optimization
====================
*/
void SWR_TimeRefresh_f (void)
{
int i;
float start, stop, time;
int startangle;
vrect_t vr;
startangle = r_refdef.viewangles[1];
start = Sys_DoubleTime ();
for (i=0 ; i<128 ; i++)
{
r_refdef.viewangles[1] = i/128.0*360.0;
VID_LockBuffer ();
R_RenderView ();
VID_UnlockBuffer ();
vr.x = r_refdef.vrect.x;
vr.y = r_refdef.vrect.y;
vr.width = r_refdef.vrect.width;
vr.height = r_refdef.vrect.height;
vr.pnext = NULL;
SWVID_Update (&vr);
}
stop = Sys_DoubleTime ();
time = stop-start;
Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
r_refdef.viewangles[1] = startangle;
}
/*
================
R_LineGraph
Only called by R_DisplayTime
================
*/
void R_LineGraph (int x, int y, int h)
{
int i;
qbyte *dest;
int s;
int color;
// FIXME: should be disabled on no-buffer adapters, or should be in the driver
// x += r_refdef.vrect.x;
// y += r_refdef.vrect.y;
dest = vid.buffer + vid.rowbytes*y + x;
s = r_graphheight.value;
if (h == 10000)
color = 0x6f; // yellow
else if (h == 9999)
color = 0x4f; // red
else if (h == 9998)
color = 0xd0; // blue
else
color = 0xff; // pink
if (h>s)
h = s;
for (i=0 ; i<h ; i++, dest -= vid.rowbytes*2)
{
dest[0] = color;
// *(dest-vid.rowbytes) = 0x30;
}
#if 0
for ( ; i<s ; i++, dest -= vid.rowbytes*2)
{
dest[0] = 0x30;
*(dest-vid.rowbytes) = 0x30;
}
#endif
}
/*
==============
R_TimeGraph
Performance monitoring tool
==============
*/
#define MAX_TIMINGS 100
extern float mouse_x, mouse_y;
int graphval;
void R_TimeGraph (void)
{
static int timex;
int a;
float r_time2;
static qbyte r_timings[MAX_TIMINGS];
int x;
r_time2 = Sys_DoubleTime ();
a = (r_time2-r_time1)/0.01;
//a = fabs(mouse_y * 0.05);
//a = (int)((r_refdef.vieworg[2] + 1024)/1)%(int)r_graphheight.value;
//a = (int)((pmove.velocity[2] + 500)/10);
//a = fabs(velocity[0])/20;
//a = ((int)fabs(origin[0])/8)%20;
//a = (cl.idealpitch + 30)/5;
//a = (int)(cl.simangles[YAW] * 64/360) & 63;
a = graphval;
r_timings[timex] = a;
a = timex;
if (r_refdef.vrect.width <= MAX_TIMINGS)
x = r_refdef.vrect.width-1;
else
x = r_refdef.vrect.width -
(r_refdef.vrect.width - MAX_TIMINGS)/2;
do
{
R_LineGraph (x, r_refdef.vrect.height-2, r_timings[a]);
if (x==0)
break; // screen too small to hold entire thing
x--;
a--;
if (a == -1)
a = MAX_TIMINGS-1;
} while (a != timex);
timex = (timex+1)%MAX_TIMINGS;
}
/*
==============
R_NetGraph
==============
*/
void SWR_NetGraph (void)
{
int a, x, y, y2, w, i;
int lost;
char st[80];
if (vid.width - 16 <= NET_TIMINGS)
w = vid.width - 16;
else
w = NET_TIMINGS;
x = -(int)((vid.width - 320)>>1);
y = vid.height - sb_lines - 24 - (int)r_graphheight.value*2 - 2;
M_DrawTextBox (x, y, (w+7)/8, ((int)r_graphheight.value*2+7)/8 + 1);
y2 = y + 8;
y = vid.height - sb_lines - 8 - 2;
x = 8;
lost = CL_CalcNet();
for (a=NET_TIMINGS-w ; a<w ; a++)
{
i = (cls.netchan.outgoing_sequence-a) & NET_TIMINGSMASK;
R_LineGraph (x+w-1-a, y, packet_latency[i]);
}
sprintf(st, "%3i%% packet loss", lost);
Draw_String(8, y2, st);
}
/*
==============
R_ZGraph
==============
*/
void R_ZGraph (void)
{
int a, x, w, i;
static int height[256];
if (r_refdef.vrect.width <= 256)
w = r_refdef.vrect.width;
else
w = 256;
height[r_framecount&255] = ((int)r_origin[2]) & 31;
x = 0;
for (a=0 ; a<w ; a++)
{
i = (r_framecount-a) & 255;
R_LineGraph (x+w-1-a, r_refdef.vrect.height-2, height[i]);
}
}
/*
=============
R_PrintTimes
=============
*/
void R_PrintTimes (void)
{
float r_time2;
float ms;
r_time2 = Sys_DoubleTime ();
ms = 1000* (r_time2 - r_time1);
Con_Printf ("%5.1f ms %3i/%3i/%3i poly %3i surf\n",
ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
c_surf = 0;
}
/*
=============
R_PrintDSpeeds
=============
*/
void R_PrintDSpeeds (void)
{
float ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, dv_time;
r_time2 = Sys_DoubleTime ();
dp_time = (dp_time2 - dp_time1) * 1000;
rw_time = (rw_time2 - rw_time1) * 1000;
db_time = (db_time2 - db_time1) * 1000;
se_time = (se_time2 - se_time1) * 1000;
de_time = (de_time2 - de_time1) * 1000;
dv_time = (dv_time2 - dv_time1) * 1000;
ms = (r_time2 - r_time1) * 1000;
Con_Printf ("%3i %4.1fp %3iw %4.1fb %3is %4.1fe %4.1fv\n",
(int)ms, dp_time, (int)rw_time, db_time, (int)se_time, de_time,
dv_time);
}
/*
=============
R_PrintAliasStats
=============
*/
void R_PrintAliasStats (void)
{
Con_Printf ("%3i polygon model drawn\n", r_amodels_drawn);
}
void WarpPalette (void)
{
int i,j;
qbyte newpalette[768];
int basecolor[3];
basecolor[0] = 130;
basecolor[1] = 80;
basecolor[2] = 50;
// pull the colors halfway to bright brown
for (i=0 ; i<256 ; i++)
{
for (j=0 ; j<3 ; j++)
{
newpalette[i*3+j] = (host_basepal[i*3+j] + basecolor[j])/2;
}
}
VID_ShiftPalette (newpalette);
}
/*
===================
R_TransformFrustum
===================
*/
void R_TransformFrustum (void)
{
int i;
vec3_t v, v2;
for (i=0 ; i<4 ; i++)
{
v[0] = screenedge[i].normal[2];
v[1] = -screenedge[i].normal[0];
v[2] = screenedge[i].normal[1];
v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
VectorCopy (v2, view_clipplanes[i].normal);
view_clipplanes[i].dist = DotProduct (modelorg, v2);
}
}
#if !id386
/*
================
TransformVector
================
*/
void TransformVector (vec3_t in, vec3_t out)
{
out[0] = DotProduct(in,vright);
out[1] = DotProduct(in,vup);
out[2] = DotProduct(in,vpn);
}
#endif
/*
================
R_TransformPlane
================
*/
void R_TransformPlane (mplane_t *p, float *normal, float *dist)
{
float d;
d = DotProduct (r_origin, p->normal);
*dist = p->dist - d;
// TODO: when we have rotating entities, this will need to use the view matrix
TransformVector (p->normal, normal);
}
/*
===============
R_SetUpFrustumIndexes
===============
*/
void R_SetUpFrustumIndexes (void)
{
int i, j, *pindex;
pindex = r_frustum_indexes;
for (i=0 ; i<4 ; i++)
{
for (j=0 ; j<3 ; j++)
{
if (view_clipplanes[i].normal[j] < 0)
{
pindex[j] = j;
pindex[j+3] = j+3;
}
else
{
pindex[j] = j+3;
pindex[j+3] = j;
}
}
// FIXME: do just once at start
pfrustum_indexes[i] = pindex;
pindex += 6;
}
}
/*
===============
R_SetupFrame
===============
*/
void SWR_SetupFrame (void)
{
static mleaf_t fakeleaf;
extern int r_dosirds;
extern int scr_chatmode;
int edgecount;
vrect_t vrect;
float w, h;
// don't allow cheats in multiplayer
if (r_numsurfs.value)
{
if ((surface_p - surfaces) > r_maxsurfsseen)
r_maxsurfsseen = surface_p - surfaces;
Con_Printf ("Used %d of %d surfs; %d max\n", surface_p - surfaces,
surf_max - surfaces, r_maxsurfsseen);
}
if (r_numedges.value)
{
edgecount = edge_p - r_edges;
if (edgecount > r_maxedgesseen)
r_maxedgesseen = edgecount;
Con_Printf ("Used %d of %d edges; %d max\n", edgecount,
r_numallocatededges, r_maxedgesseen);
}
r_refdef.ambientlight = r_ambient.value;
if (r_refdef.ambientlight < 0)
r_refdef.ambientlight = 0;
// if (!sv.active)
r_draworder.value = 0; // don't let cheaters look behind walls
R_CheckVariables ();
SWR_AnimateLight ();
r_framecount++;
numbtofpolys = 0;
// debugging
#if 0
r_refdef.vieworg[0]= 80;
r_refdef.vieworg[1]= 64;
r_refdef.vieworg[2]= 40;
r_refdef.viewangles[0]= 0;
r_refdef.viewangles[1]= 46.763641357;
r_refdef.viewangles[2]= 0;
#endif
// build the transformation matrix for the given view angles
VectorCopy (r_refdef.vieworg, modelorg);
VectorCopy (r_refdef.vieworg, r_origin);
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
if (r_refdef.flags & 1)
{
r_oldviewleaf = r_viewleaf = &fakeleaf; //so we can use quake1 rendering routines for q2 bsps.
r_viewleaf->contents = Q1CONTENTS_EMPTY;
}
else if (cl.worldmodel->fromgame == fg_quake2)
{
mleaf_t *leaf;
r_viewleaf = &fakeleaf; //so we can use quake1 rendering routines for q2 bsps.
r_viewleaf->contents = Q1CONTENTS_EMPTY;
r_oldviewcluster = r_viewcluster;
r_oldviewcluster2 = r_viewcluster2;
leaf = SWMod_PointInLeaf (r_origin, cl.worldmodel);
r_viewcluster = r_viewcluster2 = leaf->cluster;
// check above and below so crossing solid water doesn't draw wrong
if (!leaf->contents)
{ // look down a bit
vec3_t temp;
VectorCopy (r_origin, temp);
temp[2] -= 16;
leaf = SWMod_PointInLeaf (temp, cl.worldmodel);
if ( !(leaf->contents & Q2CONTENTS_SOLID) &&
(leaf->cluster != r_viewcluster2) )
r_viewcluster2 = leaf->cluster;
}
else
{ // look up a bit
vec3_t temp;
VectorCopy (r_origin, temp);
temp[2] += 16;
leaf = SWMod_PointInLeaf (temp, cl.worldmodel);
if ( !(leaf->contents & Q2CONTENTS_SOLID) &&
(leaf->cluster != r_viewcluster2) )
r_viewcluster2 = leaf->cluster;
}
}
else
{
// current viewleaf
r_oldviewleaf = r_viewleaf;
r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
}
r_dowarpold = r_dowarp;
#ifdef SIDEVIEWS
r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= Q1CONTENTS_WATER) && !r_secondaryview;
#else
r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= Q1CONTENTS_WATER);
#endif
if (vid.width > MAXWIDTH || r_pixbytes == 4 || scr_chatmode)
r_dowarp = 0;
if (r_dosirds)
r_dowarp = 0;
if ((r_dowarp != r_dowarpold) || r_viewchanged)
{
if (r_dowarp)
{
if ((vid.width <= vid.maxwarpwidth) &&
(vid.height <= vid.maxwarpheight))
{
vrect.x = 0;
vrect.y = 0;
vrect.width = vid.width;
vrect.height = vid.height;
SWR_ViewChanged (&vrect, sb_lines, vid.aspect);
}
else
{
w = vid.width;
h = vid.height;
if (w > vid.maxwarpwidth)
{
h *= (float)vid.maxwarpwidth / w;
w = vid.maxwarpwidth;
}
if (h > vid.maxwarpheight)
{
h = vid.maxwarpheight;
w *= (float)vid.maxwarpheight / h;
}
vrect.x = 0;
vrect.y = 0;
vrect.width = (int)w;
vrect.height = (int)h;
SWR_ViewChanged (&vrect,
(int)((float)sb_lines * (h/(float)vid.height)),
vid.aspect * (h / w) *
((float)vid.width / (float)vid.height));
}
}
else
{
vrect.x = 0;
vrect.y = 0;
vrect.width = vid.width;
vrect.height = vid.height;
SWR_ViewChanged (&vrect, sb_lines, vid.aspect);
}
r_viewchanged = false;
}
// start off with just the four screen edge clip planes
R_TransformFrustum ();
// save base values
VectorCopy (vpn, base_vpn);
VectorCopy (vright, base_vright);
VectorCopy (vup, base_vup);
VectorCopy (modelorg, base_modelorg);
R_SetSkyFrame ();
R_SetUpFrustumIndexes ();
r_cache_thrash = false;
// clear frame counts
c_faceclip = 0;
d_spanpixcount = 0;
r_polycount = 0;
r_drawnpolycount = 0;
r_wholepolycount = 0;
r_amodels_drawn = 0;
r_outofsurfaces = 0;
r_outofedges = 0;
D_SetupFrame ();
}

155
engine/sw/r_shared.h Normal file
View file

@ -0,0 +1,155 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef SWQUAKE
// r_shared.h: general refresh-related stuff shared between the refresh and the
// driver
// FIXME: clean up and move into d_iface.h
#ifndef _R_SHARED_H_
#define _R_SHARED_H_
#define MAXVERTS 16 // max points in a surface polygon
#define MAXWORKINGVERTS (MAXVERTS+4) // max points in an intermediate
// polygon (while processing)
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
#define MAXHEIGHT 1024
#define MAXWIDTH 1280
#define INFINITE_DISTANCE 0x10000 // distance that's always guaranteed to
// be farther away than anything in
// the scene
//===================================================================
extern void R_DrawLine (polyvert_t *polyvert0, polyvert_t *polyvert1);
extern int cachewidth;
extern int cacheheight;
extern pixel_t *cacheblock;
extern int screenwidth;
extern float pixelAspect;
extern int r_drawnpolycount;
extern cvar_t r_clearcolor;
#define SINTABLESIZE (MAXWIDTH+CYCLE)
extern int sintable[SINTABLESIZE];
extern int intsintable[SINTABLESIZE];
extern vec3_t vup, base_vup;
extern vec3_t vpn, base_vpn;
extern vec3_t vright, base_vright;
extern entity_t *currententity;
#define NUMSTACKEDGES 2000
#define MINEDGES NUMSTACKEDGES
#define NUMSTACKSURFACES 1000
#define MINSURFACES NUMSTACKSURFACES
#define MAXSPANS 3000
// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct espan_s
{
int u, v, count;
struct espan_s *pnext;
} espan_t;
// FIXME: compress, make a union if that will help
// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
typedef struct surf_s
{
struct surf_s *next; // active surface stack in r_edge.c
struct surf_s *prev; // used in r_edge.c for active surf stack
struct espan_s *spans; // pointer to linked list of spans to draw
int key; // sorting key (BSP order)
int last_u; // set during tracing
int spanstate; // 0 = not in span
// 1 = in span
// -1 = in inverted span (end before
// start)
int flags; // currentface flags
void *data; // associated data like msurface_t
entity_t *entity;
float nearzi; // nearest 1/z on surface, for mipmapping
qboolean insubmodel;
float d_ziorigin, d_zistepu, d_zistepv;
int pad[2]; // to 64 bytes
} surf_t;
extern surf_t *surfaces, *surface_p, *surf_max;
// surfaces are generated in back to front order by the bsp, so if a surf
// pointer is greater than another one, it should be drawn in front
// surfaces[1] is the background, and is used as the active surface stack.
// surfaces[0] is a dummy, because index 0 is used to indicate no surface
// attached to an edge_t
//===================================================================
extern vec3_t sxformaxis[4]; // s axis transformed into viewspace
extern vec3_t txformaxis[4]; // t axis transformed into viewspac
extern vec3_t modelorg, base_modelorg;
extern float xcenter, ycenter;
extern float xscale, yscale;
extern float xscaleinv, yscaleinv;
extern float xscaleshrink, yscaleshrink;
extern int d_lightstylevalue[256]; // 8.8 frac of base light value
extern void TransformVector (vec3_t in, vec3_t out);
extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
fixed8_t endvertu, fixed8_t endvertv);
extern int r_skymade;
extern void R_MakeSky (void);
extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
// flags in finalvert_t.flags
#define ALIAS_LEFT_CLIP 0x0001
#define ALIAS_TOP_CLIP 0x0002
#define ALIAS_RIGHT_CLIP 0x0004
#define ALIAS_BOTTOM_CLIP 0x0008
#define ALIAS_Z_CLIP 0x0010
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
#define ALIAS_ONSEAM 0x0020 // also defined in modelgen.h;
// must be kept in sync
#define ALIAS_XY_CLIP_MASK 0x000F
// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct edge_s
{
fixed16_t u;
fixed16_t u_step;
struct edge_s *prev, *next;
unsigned short surfs[2];
struct edge_s *nextremove;
float nearzi;
medge_t *owner;
} edge_t;
#endif // _R_SHARED_H_
#endif // SWQUAKE

280
engine/sw/r_sky.c Normal file
View file

@ -0,0 +1,280 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_sky.c
#include "quakedef.h"
#include "r_local.h"
#include "d_local.h"
int iskyspeed = 8;
int iskyspeed2 = 2;
float skyspeed, skyspeed2;
float skytime;
qbyte *r_skysource;
int r_skymade;
int r_skydirect; // not used?
// TODO: clean up these routines
qbyte bottomsky[128*131];
qbyte bottommask[128*131];
qbyte newsky[128*256]; // newsky and topsky both pack in here, 128 bytes
// of newsky on the left of each scan, 128 bytes
// of topsky on the right, because the low-level
// drawers need 256-qbyte scan widths
/*
=============
R_InitSky
A sky texture is 256*128, with the right side being a masked overlay
==============
*/
void SWR_InitSky (texture_t *mt)
{
int i, j;
qbyte *src;
src = (qbyte *)mt + mt->offsets[0];
for (i=0 ; i<128 ; i++)
{
for (j=0 ; j<128 ; j++)
{
newsky[(i*256) + j + 128] = src[i*256 + j + 128];
}
}
for (i=0 ; i<128 ; i++)
{
for (j=0 ; j<131 ; j++)
{
if (src[i*256 + (j & 0x7F)])
{
bottomsky[(i*131) + j] = src[i*256 + (j & 0x7F)];
bottommask[(i*131) + j] = 0;
}
else
{
bottomsky[(i*131) + j] = 0;
bottommask[(i*131) + j] = 0xff;
}
}
}
r_skysource = newsky;
}
/*
=================
R_MakeSky
=================
*/
void R_MakeSky (void)
{
int x, y;
int ofs, baseofs;
int xshift, yshift;
unsigned *pnewsky;
static int xlast = -1, ylast = -1;
xshift = skytime*skyspeed;
yshift = skytime*skyspeed;
if ((xshift == xlast) && (yshift == ylast))
return;
xlast = xshift;
ylast = yshift;
pnewsky = (unsigned *)&newsky[0];
for (y=0 ; y<SKYSIZE ; y++)
{
baseofs = ((y+yshift) & SKYMASK) * 131;
// FIXME: clean this up
#if UNALIGNED_OK
for (x=0 ; x<SKYSIZE ; x += 4)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
// PORT: unaligned dword access to bottommask and bottomsky
*pnewsky = (*(pnewsky + (128 / sizeof (unsigned))) &
*(unsigned *)&bottommask[ofs]) |
*(unsigned *)&bottomsky[ofs];
pnewsky++;
}
#else
for (x=0 ; x<SKYSIZE ; x++)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
*(qbyte *)pnewsky = (*((qbyte *)pnewsky + 128) &
*(qbyte *)&bottommask[ofs]) |
*(qbyte *)&bottomsky[ofs];
pnewsky = (unsigned *)((qbyte *)pnewsky + 1);
}
#endif
pnewsky += 128 / sizeof (unsigned);
}
r_skymade = 1;
}
/*
=================
R_GenSkyTile
=================
*/
void R_GenSkyTile (void *pdest)
{
int x, y;
int ofs, baseofs;
int xshift, yshift;
unsigned *pnewsky;
unsigned *pd;
xshift = skytime*skyspeed;
yshift = skytime*skyspeed;
pnewsky = (unsigned *)&newsky[0];
pd = (unsigned *)pdest;
for (y=0 ; y<SKYSIZE ; y++)
{
baseofs = ((y+yshift) & SKYMASK) * 131;
// FIXME: clean this up
#if UNALIGNED_OK
for (x=0 ; x<SKYSIZE ; x += 4)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
// PORT: unaligned dword access to bottommask and bottomsky
*pd = (*(pnewsky + (128 / sizeof (unsigned))) &
*(unsigned *)&bottommask[ofs]) |
*(unsigned *)&bottomsky[ofs];
pnewsky++;
pd++;
}
#else
for (x=0 ; x<SKYSIZE ; x++)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
*(qbyte *)pd = (*((qbyte *)pnewsky + 128) &
*(qbyte *)&bottommask[ofs]) |
*(qbyte *)&bottomsky[ofs];
pnewsky = (unsigned *)((qbyte *)pnewsky + 1);
pd = (unsigned *)((qbyte *)pd + 1);
}
#endif
pnewsky += 128 / sizeof (unsigned);
}
}
/*
=================
R_GenSkyTile16
=================
*/
void R_GenSkyTile16 (void *pdest)
{
int x, y;
int ofs, baseofs;
int xshift, yshift;
qbyte *pnewsky;
unsigned short *pd;
xshift = skytime * skyspeed;
yshift = skytime * skyspeed;
pnewsky = (qbyte *)&newsky[0];
pd = (unsigned short *)pdest;
for (y=0 ; y<SKYSIZE ; y++)
{
baseofs = ((y+yshift) & SKYMASK) * 131;
// FIXME: clean this up
// FIXME: do faster unaligned version?
for (x=0 ; x<SKYSIZE ; x++)
{
ofs = baseofs + ((x+xshift) & SKYMASK);
*pd = d_8to16table[(*(pnewsky + 128) &
*(qbyte *)&bottommask[ofs]) |
*(qbyte *)&bottomsky[ofs]];
pnewsky++;
pd++;
}
pnewsky += TILE_SIZE;
}
}
/*
=============
R_SetSkyFrame
==============
*/
void R_SetSkyFrame (void)
{
int g, s1, s2;
float temp;
skyspeed = iskyspeed;
skyspeed2 = iskyspeed2;
g = GreatestCommonDivisor (iskyspeed, iskyspeed2);
s1 = iskyspeed / g;
s2 = iskyspeed2 / g;
temp = SKYSIZE * s1 * s2;
skytime = cl.time - ((int)(cl.time / temp) * temp);
r_skymade = 0;
}

401
engine/sw/r_sprite.c Normal file
View file

@ -0,0 +1,401 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_sprite.c
#include "quakedef.h"
#include "r_local.h"
static int clip_current;
static vec5_t clip_verts[2][MAXWORKINGVERTS];
static int sprite_width, sprite_height;
spritedesc_t r_spritedesc;
/*
================
R_RotateSprite
================
*/
void R_RotateSprite (float beamlength)
{
vec3_t vec;
if (beamlength == 0.0)
return;
VectorScale (r_spritedesc.vpn, -beamlength, vec);
VectorAdd (r_entorigin, vec, r_entorigin);
VectorSubtract (modelorg, vec, modelorg);
}
/*
=============
R_ClipSpriteFace
Clips the winding at clip_verts[clip_current] and changes clip_current
Throws out the back side
==============
*/
int R_ClipSpriteFace (int nump, clipplane_t *pclipplane)
{
int i, outcount;
float dists[MAXWORKINGVERTS+1];
float frac, clipdist, *pclipnormal;
float *in, *instep, *outstep, *vert2;
clipdist = pclipplane->dist;
pclipnormal = pclipplane->normal;
// calc dists
if (clip_current)
{
in = clip_verts[1][0];
outstep = clip_verts[0][0];
clip_current = 0;
}
else
{
in = clip_verts[0][0];
outstep = clip_verts[1][0];
clip_current = 1;
}
instep = in;
for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
{
dists[i] = DotProduct (instep, pclipnormal) - clipdist;
}
// handle wraparound case
dists[nump] = dists[0];
Q_memcpy (instep, in, sizeof (vec5_t));
// clip the winding
instep = in;
outcount = 0;
for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
{
if (dists[i] >= 0)
{
Q_memcpy (outstep, instep, sizeof (vec5_t));
outstep += sizeof (vec5_t) / sizeof (float);
outcount++;
}
if (dists[i] == 0 || dists[i+1] == 0)
continue;
if ( (dists[i] > 0) == (dists[i+1] > 0) )
continue;
// split it into a new vertex
frac = dists[i] / (dists[i] - dists[i+1]);
vert2 = instep + sizeof (vec5_t) / sizeof (float);
outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
outstep += sizeof (vec5_t) / sizeof (float);
outcount++;
}
return outcount;
}
/*
================
R_SetupAndDrawSprite
================
*/
void R_SetupAndDrawSprite ()
{
int i, nump;
float dot, scale, *pv;
vec5_t *pverts;
vec3_t left, up, right, down, transformed, local;
emitpoint_t outverts[MAXWORKINGVERTS+1], *pout;
dot = DotProduct (r_spritedesc.vpn, modelorg);
// backface cull
if (dot >= 0)
return;
// build the sprite poster in worldspace
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
pverts = clip_verts[0];
pverts[0][0] = r_entorigin[0] + up[0] + left[0];
pverts[0][1] = r_entorigin[1] + up[1] + left[1];
pverts[0][2] = r_entorigin[2] + up[2] + left[2];
pverts[0][3] = 0;
pverts[0][4] = 0;
pverts[1][0] = r_entorigin[0] + up[0] + right[0];
pverts[1][1] = r_entorigin[1] + up[1] + right[1];
pverts[1][2] = r_entorigin[2] + up[2] + right[2];
pverts[1][3] = sprite_width;
pverts[1][4] = 0;
pverts[2][0] = r_entorigin[0] + down[0] + right[0];
pverts[2][1] = r_entorigin[1] + down[1] + right[1];
pverts[2][2] = r_entorigin[2] + down[2] + right[2];
pverts[2][3] = sprite_width;
pverts[2][4] = sprite_height;
pverts[3][0] = r_entorigin[0] + down[0] + left[0];
pverts[3][1] = r_entorigin[1] + down[1] + left[1];
pverts[3][2] = r_entorigin[2] + down[2] + left[2];
pverts[3][3] = 0;
pverts[3][4] = sprite_height;
// clip to the frustum in worldspace
nump = 4;
clip_current = 0;
for (i=0 ; i<4 ; i++)
{
nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
if (nump < 3)
return;
if (nump >= MAXWORKINGVERTS)
Sys_Error("R_SetupAndDrawSprite: too many points");
}
// transform vertices into viewspace and project
pv = &clip_verts[clip_current][0][0];
r_spritedesc.nearzi = -999999;
for (i=0 ; i<nump ; i++)
{
VectorSubtract (pv, r_origin, local);
TransformVector (local, transformed);
if (transformed[2] < NEAR_CLIP)
transformed[2] = NEAR_CLIP;
pout = &outverts[i];
pout->zi = 1.0 / transformed[2];
if (pout->zi > r_spritedesc.nearzi)
r_spritedesc.nearzi = pout->zi;
pout->s = pv[3];
pout->t = pv[4];
scale = xscale * pout->zi;
pout->u = (xcenter + scale * transformed[0]);
scale = yscale * pout->zi;
pout->v = (ycenter - scale * transformed[1]);
pv += sizeof (vec5_t) / sizeof (pv);
}
// draw it
r_spritedesc.nump = nump;
r_spritedesc.pverts = outverts;
D_DrawSprite ();
}
/*
================
R_GetSpriteframe
================
*/
mspriteframe_t *R_GetSpriteframe (msprite_t *psprite)
{
mspritegroup_t *pspritegroup;
mspriteframe_t *pspriteframe;
int i, numframes, frame;
float *pintervals, fullinterval, targettime, time;
frame = currententity->frame;
if ((frame >= psprite->numframes) || (frame < 0))
{
Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
frame = 0;
}
if (psprite->frames[frame].type == SPR_SINGLE)
{
pspriteframe = psprite->frames[frame].frameptr;
}
else
{
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
pintervals = pspritegroup->intervals;
numframes = pspritegroup->numframes;
fullinterval = pintervals[numframes-1];
time = cl.time + currententity->syncbase;
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
// are positive, so we don't have to worry about division by 0
targettime = time - ((int)(time / fullinterval)) * fullinterval;
for (i=0 ; i<(numframes-1) ; i++)
{
if (pintervals[i] > targettime)
break;
}
pspriteframe = pspritegroup->frames[i];
}
return pspriteframe;
}
/*
================
R_DrawSprite
================
*/
void R_DrawSprite (void)
{
int i;
msprite_t *psprite;
vec3_t tvec;
float dot, angle, sr, cr;
psprite = currententity->model->cache.data;
r_spritedesc.pspriteframe = R_GetSpriteframe (psprite);
sprite_width = r_spritedesc.pspriteframe->width;
sprite_height = r_spritedesc.pspriteframe->height;
// TODO: make this caller-selectable
if (psprite->type == SPR_FACING_UPRIGHT)
{
// generate the sprite's axes, with vup straight up in worldspace, and
// r_spritedesc.vright perpendicular to modelorg.
// This will not work if the view direction is very close to straight up or
// down, because the cross product will be between two nearly parallel
// vectors and starts to approach an undefined state, so we don't draw if
// the two vectors are less than 1 degree apart
tvec[0] = -modelorg[0];
tvec[1] = -modelorg[1];
tvec[2] = -modelorg[2];
VectorNormalize (tvec);
dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
// r_spritedesc.vup is 0, 0, 1
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
return;
r_spritedesc.vup[0] = 0;
r_spritedesc.vup[1] = 0;
r_spritedesc.vup[2] = 1;
r_spritedesc.vright[0] = tvec[1];
// CrossProduct(r_spritedesc.vup, -modelorg,
r_spritedesc.vright[1] = -tvec[0];
// r_spritedesc.vright)
r_spritedesc.vright[2] = 0;
VectorNormalize (r_spritedesc.vright);
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
r_spritedesc.vpn[2] = 0;
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
// r_spritedesc.vpn)
}
else if (psprite->type == SPR_VP_PARALLEL)
{
// generate the sprite's axes, completely parallel to the viewplane. There
// are no problem situations, because the sprite is always in the same
// position relative to the viewer
for (i=0 ; i<3 ; i++)
{
r_spritedesc.vup[i] = vup[i];
r_spritedesc.vright[i] = vright[i];
r_spritedesc.vpn[i] = vpn[i];
}
}
else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT)
{
// generate the sprite's axes, with vup straight up in worldspace, and
// r_spritedesc.vright parallel to the viewplane.
// This will not work if the view direction is very close to straight up or
// down, because the cross product will be between two nearly parallel
// vectors and starts to approach an undefined state, so we don't draw if
// the two vectors are less than 1 degree apart
dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
// r_spritedesc.vup is 0, 0, 1
if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
return;
r_spritedesc.vup[0] = 0;
r_spritedesc.vup[1] = 0;
r_spritedesc.vup[2] = 1;
r_spritedesc.vright[0] = vpn[1];
// CrossProduct (r_spritedesc.vup, vpn,
r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright)
r_spritedesc.vright[2] = 0;
VectorNormalize (r_spritedesc.vright);
r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
r_spritedesc.vpn[1] = r_spritedesc.vright[0];
r_spritedesc.vpn[2] = 0;
// CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
// r_spritedesc.vpn)
}
else if (psprite->type == SPR_ORIENTED)
{
// generate the sprite's axes, according to the sprite's world orientation
AngleVectors (currententity->angles, r_spritedesc.vpn,
r_spritedesc.vright, r_spritedesc.vup);
}
else if (psprite->type == SPR_VP_PARALLEL_ORIENTED)
{
// generate the sprite's axes, parallel to the viewplane, but rotated in
// that plane around the center according to the sprite entity's roll
// angle. So vpn stays the same, but vright and vup rotate
angle = currententity->angles[ROLL] * (M_PI*2 / 360);
sr = sin(angle);
cr = cos(angle);
for (i=0 ; i<3 ; i++)
{
r_spritedesc.vpn[i] = vpn[i];
r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
}
}
else
{
Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
}
R_RotateSprite (psprite->beamlength);
R_SetupAndDrawSprite ();
}

1604
engine/sw/r_surf.c Normal file

File diff suppressed because it is too large Load diff

39
engine/sw/r_vars.c Normal file
View file

@ -0,0 +1,39 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_vars.c: global refresh variables
#include "quakedef.h"
#if !id386
// all global and static refresh variables are collected in a contiguous block
// to avoid cache conflicts.
//-------------------------------------------------------
// global refresh variables
//-------------------------------------------------------
// FIXME: make into one big structure, like cl or sv
// FIXME: do separately for refresh engine and driver
int r_bmodelactive;
#endif // !id386

64
engine/sw/r_varsa.s Normal file
View file

@ -0,0 +1,64 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// r_varsa.s
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#include "d_ifacea.h"
#if id386
.data
//-------------------------------------------------------
// ASM-only variables
//-------------------------------------------------------
.globl float_1, float_particle_z_clip, float_point5
.globl float_minus_1, float_0
float_0: .single 0.0
float_1: .single 1.0
float_minus_1: .single -1.0
float_particle_z_clip: .single PARTICLE_Z_CLIP
float_point5: .single 0.5
.globl fp_16, fp_64k, fp_1m, fp_64kx64k
.globl fp_1m_minus_1
.globl fp_8
fp_1m: .single 1048576.0
fp_1m_minus_1: .single 1048575.0
fp_64k: .single 65536.0
fp_8: .single 8.0
fp_16: .single 16.0
fp_64kx64k: .long 0x4f000000 // (float)0x8000*0x10000
.globl FloatZero, Float2ToThe31nd, FloatMinus2ToThe31nd
FloatZero: .long 0
Float2ToThe31nd: .long 0x4f000000
FloatMinus2ToThe31nd: .long 0xcf000000
.globl C(r_bmodelactive)
C(r_bmodelactive): .long 0
#endif // id386

172
engine/sw/surf16.s Normal file
View file

@ -0,0 +1,172 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// surf16.s
// x86 assembly-language 16 bpp surface block drawing code.
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#if id386
//----------------------------------------------------------------------
// Surface block drawer
//----------------------------------------------------------------------
.data
k: .long 0
loopentry: .long 0
.align 4
blockjumptable16:
.long LEnter2_16
.long LEnter4_16
.long 0, LEnter8_16
.long 0, 0, 0, LEnter16_16
.text
.align 4
.globl C(R_Surf16Start)
C(R_Surf16Start):
.align 4
.globl C(R_DrawSurfaceBlock16)
C(R_DrawSurfaceBlock16):
pushl %ebp // preserve caller's stack frame
pushl %edi
pushl %esi // preserve register variables
pushl %ebx
movl C(blocksize),%eax
movl C(prowdestbase),%edi
movl C(pbasesource),%esi
movl C(sourcesstep),%ebx
movl blockjumptable16-4(,%eax,2),%ecx
movl %eax,k
movl %ecx,loopentry
movl C(lightleft),%edx
movl C(lightright),%ebp
Lblockloop16:
subl %edx,%ebp
movb C(blockdivshift),%cl
sarl %cl,%ebp
jns Lp1_16
testl C(blockdivmask),%ebp
jz Lp1_16
incl %ebp
Lp1_16:
subl %eax,%eax
subl %ecx,%ecx // high words must be 0 in loop for addressing
jmp *loopentry
.align 4
#include "block16.h"
movl C(pbasesource),%esi
movl C(lightleft),%edx
movl C(lightright),%ebp
movl C(sourcetstep),%eax
movl C(lightrightstep),%ecx
movl C(prowdestbase),%edi
addl %eax,%esi
addl %ecx,%ebp
movl C(lightleftstep),%eax
movl C(surfrowbytes),%ecx
addl %eax,%edx
addl %ecx,%edi
movl %esi,C(pbasesource)
movl %ebp,C(lightright)
movl k,%eax
movl %edx,C(lightleft)
decl %eax
movl %edi,C(prowdestbase)
movl %eax,k
jnz Lblockloop16
popl %ebx // restore register variables
popl %esi
popl %edi
popl %ebp // restore the caller's stack frame
ret
.globl C(R_Surf16End)
C(R_Surf16End):
//----------------------------------------------------------------------
// Code patching routines
//----------------------------------------------------------------------
.data
.align 4
LPatchTable16:
.long LBPatch0-4
.long LBPatch1-4
.long LBPatch2-4
.long LBPatch3-4
.long LBPatch4-4
.long LBPatch5-4
.long LBPatch6-4
.long LBPatch7-4
.long LBPatch8-4
.long LBPatch9-4
.long LBPatch10-4
.long LBPatch11-4
.long LBPatch12-4
.long LBPatch13-4
.long LBPatch14-4
.long LBPatch15-4
.text
.align 4
.globl C(R_Surf16Patch)
C(R_Surf16Patch):
pushl %ebx
movl C(colormap),%eax
movl $LPatchTable16,%ebx
movl $16,%ecx
LPatchLoop16:
movl (%ebx),%edx
addl $4,%ebx
movl %eax,(%edx)
decl %ecx
jnz LPatchLoop16
popl %ebx
ret
#endif // id386

783
engine/sw/surf8.s Normal file
View file

@ -0,0 +1,783 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//
// surf8.s
// x86 assembly-language 8 bpp surface block drawing code.
//
#include "asm_i386.h"
#include "quakeasm.h"
#include "asm_draw.h"
#if id386
.data
sb_v: .long 0
.text
.align 4
.globl C(R_Surf8Start)
C(R_Surf8Start):
//----------------------------------------------------------------------
// Surface block drawer for mip level 0
//----------------------------------------------------------------------
.align 4
.globl C(R_DrawSurfaceBlock8_mip0)
C(R_DrawSurfaceBlock8_mip0):
pushl %ebp // preserve caller's stack frame
pushl %edi
pushl %esi // preserve register variables
pushl %ebx
// for (v=0 ; v<numvblocks ; v++)
// {
movl C(r_lightptr),%ebx
movl C(r_numvblocks),%eax
movl %eax,sb_v
movl C(prowdestbase),%edi
movl C(pbasesource),%esi
Lv_loop_mip0:
// lightleft = lightptr[0];
// lightright = lightptr[1];
// lightdelta = (lightleft - lightright) & 0xFFFFF;
movl (%ebx),%eax // lightleft
movl 4(%ebx),%edx // lightright
movl %eax,%ebp
movl C(r_lightwidth),%ecx
movl %edx,C(lightright)
subl %edx,%ebp
andl $0xFFFFF,%ebp
leal (%ebx,%ecx,4),%ebx
// lightptr += lightwidth;
movl %ebx,C(r_lightptr)
// lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
// lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
// 0xF0000000;
movl 4(%ebx),%ecx // lightptr[1]
movl (%ebx),%ebx // lightptr[0]
subl %eax,%ebx
subl %edx,%ecx
sarl $4,%ecx
orl $0xF0000000,%ebp
sarl $4,%ebx
movl %ecx,C(lightrightstep)
subl %ecx,%ebx
andl $0xFFFFF,%ebx
orl $0xF0000000,%ebx
subl %ecx,%ecx // high word must be 0 in loop for addressing
movl %ebx,C(lightdeltastep)
subl %ebx,%ebx // high word must be 0 in loop for addressing
Lblockloop8_mip0:
movl %ebp,C(lightdelta)
movb 14(%esi),%cl
sarl $4,%ebp
movb %dh,%bh
movb 15(%esi),%bl
addl %ebp,%edx
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch0:
movb 13(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch1:
movb 12(%esi),%cl
movb %dh,%bh
addl %ebp,%edx
rorl $16,%eax
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch2:
movb 11(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch3:
movb 10(%esi),%cl
movl %eax,12(%edi)
movb %dh,%bh
addl %ebp,%edx
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch4:
movb 9(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch5:
movb 8(%esi),%cl
movb %dh,%bh
addl %ebp,%edx
rorl $16,%eax
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch6:
movb 7(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch7:
movb 6(%esi),%cl
movl %eax,8(%edi)
movb %dh,%bh
addl %ebp,%edx
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch8:
movb 5(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch9:
movb 4(%esi),%cl
movb %dh,%bh
addl %ebp,%edx
rorl $16,%eax
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch10:
movb 3(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch11:
movb 2(%esi),%cl
movl %eax,4(%edi)
movb %dh,%bh
addl %ebp,%edx
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch12:
movb 1(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch13:
movb (%esi),%cl
movb %dh,%bh
addl %ebp,%edx
rorl $16,%eax
movb %dh,%ch
movb 0x12345678(%ebx),%ah
LBPatch14:
movl C(lightright),%edx
movb 0x12345678(%ecx),%al
LBPatch15:
movl C(lightdelta),%ebp
movl %eax,(%edi)
addl C(sourcetstep),%esi
addl C(surfrowbytes),%edi
addl C(lightrightstep),%edx
addl C(lightdeltastep),%ebp
movl %edx,C(lightright)
jc Lblockloop8_mip0
// if (pbasesource >= r_sourcemax)
// pbasesource -= stepback;
cmpl C(r_sourcemax),%esi
jb LSkip_mip0
subl C(r_stepback),%esi
LSkip_mip0:
movl C(r_lightptr),%ebx
decl sb_v
jnz Lv_loop_mip0
popl %ebx // restore register variables
popl %esi
popl %edi
popl %ebp // restore the caller's stack frame
ret
//----------------------------------------------------------------------
// Surface block drawer for mip level 1
//----------------------------------------------------------------------
.align 4
.globl C(R_DrawSurfaceBlock8_mip1)
C(R_DrawSurfaceBlock8_mip1):
pushl %ebp // preserve caller's stack frame
pushl %edi
pushl %esi // preserve register variables
pushl %ebx
// for (v=0 ; v<numvblocks ; v++)
// {
movl C(r_lightptr),%ebx
movl C(r_numvblocks),%eax
movl %eax,sb_v
movl C(prowdestbase),%edi
movl C(pbasesource),%esi
Lv_loop_mip1:
// lightleft = lightptr[0];
// lightright = lightptr[1];
// lightdelta = (lightleft - lightright) & 0xFFFFF;
movl (%ebx),%eax // lightleft
movl 4(%ebx),%edx // lightright
movl %eax,%ebp
movl C(r_lightwidth),%ecx
movl %edx,C(lightright)
subl %edx,%ebp
andl $0xFFFFF,%ebp
leal (%ebx,%ecx,4),%ebx
// lightptr += lightwidth;
movl %ebx,C(r_lightptr)
// lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
// lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
// 0xF0000000;
movl 4(%ebx),%ecx // lightptr[1]
movl (%ebx),%ebx // lightptr[0]
subl %eax,%ebx
subl %edx,%ecx
sarl $3,%ecx
orl $0x70000000,%ebp
sarl $3,%ebx
movl %ecx,C(lightrightstep)
subl %ecx,%ebx
andl $0xFFFFF,%ebx
orl $0xF0000000,%ebx
subl %ecx,%ecx // high word must be 0 in loop for addressing
movl %ebx,C(lightdeltastep)
subl %ebx,%ebx // high word must be 0 in loop for addressing
Lblockloop8_mip1:
movl %ebp,C(lightdelta)
movb 6(%esi),%cl
sarl $3,%ebp
movb %dh,%bh
movb 7(%esi),%bl
addl %ebp,%edx
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch22:
movb 5(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch23:
movb 4(%esi),%cl
movb %dh,%bh
addl %ebp,%edx
rorl $16,%eax
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch24:
movb 3(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch25:
movb 2(%esi),%cl
movl %eax,4(%edi)
movb %dh,%bh
addl %ebp,%edx
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch26:
movb 1(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch27:
movb (%esi),%cl
movb %dh,%bh
addl %ebp,%edx
rorl $16,%eax
movb %dh,%ch
movb 0x12345678(%ebx),%ah
LBPatch28:
movl C(lightright),%edx
movb 0x12345678(%ecx),%al
LBPatch29:
movl C(lightdelta),%ebp
movl %eax,(%edi)
movl C(sourcetstep),%eax
addl %eax,%esi
movl C(surfrowbytes),%eax
addl %eax,%edi
movl C(lightrightstep),%eax
addl %eax,%edx
movl C(lightdeltastep),%eax
addl %eax,%ebp
movl %edx,C(lightright)
jc Lblockloop8_mip1
// if (pbasesource >= r_sourcemax)
// pbasesource -= stepback;
cmpl C(r_sourcemax),%esi
jb LSkip_mip1
subl C(r_stepback),%esi
LSkip_mip1:
movl C(r_lightptr),%ebx
decl sb_v
jnz Lv_loop_mip1
popl %ebx // restore register variables
popl %esi
popl %edi
popl %ebp // restore the caller's stack frame
ret
//----------------------------------------------------------------------
// Surface block drawer for mip level 2
//----------------------------------------------------------------------
.align 4
.globl C(R_DrawSurfaceBlock8_mip2)
C(R_DrawSurfaceBlock8_mip2):
pushl %ebp // preserve caller's stack frame
pushl %edi
pushl %esi // preserve register variables
pushl %ebx
// for (v=0 ; v<numvblocks ; v++)
// {
movl C(r_lightptr),%ebx
movl C(r_numvblocks),%eax
movl %eax,sb_v
movl C(prowdestbase),%edi
movl C(pbasesource),%esi
Lv_loop_mip2:
// lightleft = lightptr[0];
// lightright = lightptr[1];
// lightdelta = (lightleft - lightright) & 0xFFFFF;
movl (%ebx),%eax // lightleft
movl 4(%ebx),%edx // lightright
movl %eax,%ebp
movl C(r_lightwidth),%ecx
movl %edx,C(lightright)
subl %edx,%ebp
andl $0xFFFFF,%ebp
leal (%ebx,%ecx,4),%ebx
// lightptr += lightwidth;
movl %ebx,C(r_lightptr)
// lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
// lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
// 0xF0000000;
movl 4(%ebx),%ecx // lightptr[1]
movl (%ebx),%ebx // lightptr[0]
subl %eax,%ebx
subl %edx,%ecx
sarl $2,%ecx
orl $0x30000000,%ebp
sarl $2,%ebx
movl %ecx,C(lightrightstep)
subl %ecx,%ebx
andl $0xFFFFF,%ebx
orl $0xF0000000,%ebx
subl %ecx,%ecx // high word must be 0 in loop for addressing
movl %ebx,C(lightdeltastep)
subl %ebx,%ebx // high word must be 0 in loop for addressing
Lblockloop8_mip2:
movl %ebp,C(lightdelta)
movb 2(%esi),%cl
sarl $2,%ebp
movb %dh,%bh
movb 3(%esi),%bl
addl %ebp,%edx
movb %dh,%ch
addl %ebp,%edx
movb 0x12345678(%ebx),%ah
LBPatch18:
movb 1(%esi),%bl
movb 0x12345678(%ecx),%al
LBPatch19:
movb (%esi),%cl
movb %dh,%bh
addl %ebp,%edx
rorl $16,%eax
movb %dh,%ch
movb 0x12345678(%ebx),%ah
LBPatch20:
movl C(lightright),%edx
movb 0x12345678(%ecx),%al
LBPatch21:
movl C(lightdelta),%ebp
movl %eax,(%edi)
movl C(sourcetstep),%eax
addl %eax,%esi
movl C(surfrowbytes),%eax
addl %eax,%edi
movl C(lightrightstep),%eax
addl %eax,%edx
movl C(lightdeltastep),%eax
addl %eax,%ebp
movl %edx,C(lightright)
jc Lblockloop8_mip2
// if (pbasesource >= r_sourcemax)
// pbasesource -= stepback;
cmpl C(r_sourcemax),%esi
jb LSkip_mip2
subl C(r_stepback),%esi
LSkip_mip2:
movl C(r_lightptr),%ebx
decl sb_v
jnz Lv_loop_mip2
popl %ebx // restore register variables
popl %esi
popl %edi
popl %ebp // restore the caller's stack frame
ret
//----------------------------------------------------------------------
// Surface block drawer for mip level 3
//----------------------------------------------------------------------
.align 4
.globl C(R_DrawSurfaceBlock8_mip3)
C(R_DrawSurfaceBlock8_mip3):
pushl %ebp // preserve caller's stack frame
pushl %edi
pushl %esi // preserve register variables
pushl %ebx
// for (v=0 ; v<numvblocks ; v++)
// {
movl C(r_lightptr),%ebx
movl C(r_numvblocks),%eax
movl %eax,sb_v
movl C(prowdestbase),%edi
movl C(pbasesource),%esi
Lv_loop_mip3:
// lightleft = lightptr[0];
// lightright = lightptr[1];
// lightdelta = (lightleft - lightright) & 0xFFFFF;
movl (%ebx),%eax // lightleft
movl 4(%ebx),%edx // lightright
movl %eax,%ebp
movl C(r_lightwidth),%ecx
movl %edx,C(lightright)
subl %edx,%ebp
andl $0xFFFFF,%ebp
leal (%ebx,%ecx,4),%ebx
movl %ebp,C(lightdelta)
// lightptr += lightwidth;
movl %ebx,C(r_lightptr)
// lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
// lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
// lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
// 0xF0000000;
movl 4(%ebx),%ecx // lightptr[1]
movl (%ebx),%ebx // lightptr[0]
subl %eax,%ebx
subl %edx,%ecx
sarl $1,%ecx
sarl $1,%ebx
movl %ecx,C(lightrightstep)
subl %ecx,%ebx
andl $0xFFFFF,%ebx
sarl $1,%ebp
orl $0xF0000000,%ebx
movl %ebx,C(lightdeltastep)
subl %ebx,%ebx // high word must be 0 in loop for addressing
movb 1(%esi),%bl
subl %ecx,%ecx // high word must be 0 in loop for addressing
movb %dh,%bh
movb (%esi),%cl
addl %ebp,%edx
movb %dh,%ch
movb 0x12345678(%ebx),%al
LBPatch16:
movl C(lightright),%edx
movb %al,1(%edi)
movb 0x12345678(%ecx),%al
LBPatch17:
movb %al,(%edi)
movl C(sourcetstep),%eax
addl %eax,%esi
movl C(surfrowbytes),%eax
addl %eax,%edi
movl C(lightdeltastep),%eax
movl C(lightdelta),%ebp
movb (%esi),%cl
addl %eax,%ebp
movl C(lightrightstep),%eax
sarl $1,%ebp
addl %eax,%edx
movb %dh,%bh
movb 1(%esi),%bl
addl %ebp,%edx
movb %dh,%ch
movb 0x12345678(%ebx),%al
LBPatch30:
movl C(sourcetstep),%edx
movb %al,1(%edi)
movb 0x12345678(%ecx),%al
LBPatch31:
movb %al,(%edi)
movl C(surfrowbytes),%ebp
addl %edx,%esi
addl %ebp,%edi
// if (pbasesource >= r_sourcemax)
// pbasesource -= stepback;
cmpl C(r_sourcemax),%esi
jb LSkip_mip3
subl C(r_stepback),%esi
LSkip_mip3:
movl C(r_lightptr),%ebx
decl sb_v
jnz Lv_loop_mip3
popl %ebx // restore register variables
popl %esi
popl %edi
popl %ebp // restore the caller's stack frame
ret
.globl C(R_Surf8End)
C(R_Surf8End):
//----------------------------------------------------------------------
// Code patching routines
//----------------------------------------------------------------------
.data
.align 4
LPatchTable8:
.long LBPatch0-4
.long LBPatch1-4
.long LBPatch2-4
.long LBPatch3-4
.long LBPatch4-4
.long LBPatch5-4
.long LBPatch6-4
.long LBPatch7-4
.long LBPatch8-4
.long LBPatch9-4
.long LBPatch10-4
.long LBPatch11-4
.long LBPatch12-4
.long LBPatch13-4
.long LBPatch14-4
.long LBPatch15-4
.long LBPatch16-4
.long LBPatch17-4
.long LBPatch18-4
.long LBPatch19-4
.long LBPatch20-4
.long LBPatch21-4
.long LBPatch22-4
.long LBPatch23-4
.long LBPatch24-4
.long LBPatch25-4
.long LBPatch26-4
.long LBPatch27-4
.long LBPatch28-4
.long LBPatch29-4
.long LBPatch30-4
.long LBPatch31-4
.text
.align 4
.globl C(R_Surf8Patch)
C(R_Surf8Patch):
pushl %ebx
movl C(colormap),%eax
movl $LPatchTable8,%ebx
movl $32,%ecx
LPatchLoop8:
movl (%ebx),%edx
addl $4,%ebx
movl %eax,(%edx)
decl %ecx
jnz LPatchLoop8
popl %ebx
ret
#endif // id386

2301
engine/sw/sw_draw.c Normal file

File diff suppressed because it is too large Load diff

48
engine/sw/sw_draw.h Normal file
View file

@ -0,0 +1,48 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// draw.h -- these are the only functions outside the refresh allowed
// to touch the vid buffer
void SWDraw_Init (void);
void SWDraw_ReInit (void);
void SWDraw_Shutdown(void);
void SWDraw_Character (int x, int y, unsigned int num);
void SWDraw_ColouredCharacter (int x, int y, unsigned int num);
void SWDraw_DebugChar (qbyte num);
void SWDraw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height);
void SWDraw_Pic (int x, int y, qpic_t *pic);
void SWDraw_TransPic (int x, int y, qpic_t *pic);
void SWDraw_TransPicTranslate (int x, int y, qpic_t *pic, qbyte *translation);
void SWDraw_ConsoleBackground (int lines);
void SWDraw_EditorBackground (int lines);
void SWDraw_BeginDisc (void);
void SWDraw_EndDisc (void);
void SWDraw_TileClear (int x, int y, int w, int h);
void SWDraw_Fill (int x, int y, int w, int h, int c);
void SWDraw_FadeScreen (void);
void SWDraw_String (int x, int y, const qbyte *str);
void SWDraw_Alt_String (int x, int y, const qbyte *str);
qpic_t *SWDraw_SafePicFromWad (char *name);
qpic_t *SWDraw_PicFromWad (char *name);
qpic_t *SWDraw_SafeCachePic (char *path);
qpic_t *SWDraw_CachePic (char *path);
void SWDraw_Crosshair(void);

3610
engine/sw/sw_model.c Normal file

File diff suppressed because it is too large Load diff

303
engine/sw/sw_screen.c Normal file
View file

@ -0,0 +1,303 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// screen.c -- master for refresh, status bar, console, chat, notify, etc
#include "quakedef.h"
#include "r_local.h"
extern qboolean scr_drawdialog;
extern cvar_t gl_triplebuffer;
extern cvar_t scr_fov;
extern qboolean scr_initialized;
extern float oldsbar;
extern qboolean scr_drawloading;
extern float oldfov, oldscreensize;
extern int scr_chatmode;
extern cvar_t scr_chatmodecvar;
/*
==================
SCR_UpdateScreen
This is called every frame, and can also be called explicitly to flush
text to the screen.
WARNING: be very careful calling this from elsewhere, because the refresh
needs almost the entire 256k of stack space!
==================
*/
void SWSCR_UpdateScreen (void)
{
int uimenu;
vrect_t vrect;
if (scr_skipupdate || block_drawing)
return;
if (scr_disabled_for_loading)
{
if (key_dest != key_console)
return;
}
#ifdef _WIN32
{ // don't suck up any cpu if minimized
extern int Minimized;
if (Minimized)
return;
}
#endif
scr_copytop = 0;
scr_copyeverything = 0;
if (!scr_initialized || !con_initialized)
return; // not initialized yet
uimenu = UI_MenuState();
//
// check for vid changes
//
if (oldfov != scr_fov.value)
{
oldfov = scr_fov.value;
vid.recalc_refdef = true;
}
if (scr_chatmode != scr_chatmodecvar.value)
vid.recalc_refdef = true;
if (oldsbar != cl_sbar.value)
{
oldsbar = cl_sbar.value;
vid.recalc_refdef = true;
}
#ifdef TEXTEDITOR
if (editormodal)
{
Editor_Draw();
SWV_UpdatePalette ();
vrect.x = 0;
vrect.y = 0;
vrect.width = vid.width;
vrect.height = vid.height;
vrect.pnext = 0;
SWVID_Update (&vrect);
return;
}
#endif
if (Media_ShowFilm())
{
SWV_UpdatePalette ();
vrect.x = 0;
vrect.y = 0;
vrect.width = vid.width;
vrect.height = vid.height;
vrect.pnext = 0;
SWVID_Update (&vrect);
return;
}
if (vid.recalc_refdef || scr_viewsize.modified)
{
// something changed, so reorder the screen
SCR_CalcRefdef ();
}
//
// do 3D refresh drawing, and then update the screen
//
D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
SCR_TileClear();
SCR_SetUpToDrawConsole ();
SCR_EraseCenterString ();
D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
// for linear writes all the time
#ifdef TEXTEDIT
if (!editormodal) //don't render view.
#endif
if (cl.worldmodel)
{
VID_LockBuffer ();
V_RenderView ();
VID_UnlockBuffer ();
}
D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
if (scr_drawloading)
{
SCR_DrawLoading ();
Sbar_Draw ();
}
else if (scr_drawdialog)
{
Sbar_Draw ();
Draw_FadeScreen ();
SCR_DrawNotifyString ();
scr_copyeverything = true;
}
else if (cl.intermission == 1 && key_dest == key_game)
{
Sbar_IntermissionOverlay ();
}
else if (cl.intermission == 2 && key_dest == key_game)
{
Sbar_FinaleOverlay ();
SCR_CheckDrawCenterString ();
}
else
{
Draw_Crosshair();
SCR_DrawRam ();
SCR_DrawNet ();
SCR_DrawTurtle ();
SCR_DrawPause ();
SCR_DrawFPS ();
SCR_CheckDrawCenterString ();
Sbar_Draw ();
#ifdef TEXTEDITOR
if (editoractive)
Editor_Draw();
#endif
SCR_DrawConsole (false);
M_Draw (uimenu);
}
D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
// for linear writes all the time
SWV_UpdatePalette ();
//
// update one of three areas
//
if (scr_copyeverything)
{
vrect.x = 0;
vrect.y = 0;
vrect.width = vid.width;
vrect.height = vid.height;
vrect.pnext = 0;
SWVID_Update (&vrect);
}
else if (scr_copytop)
{
vrect.x = 0;
vrect.y = 0;
vrect.width = vid.width;
vrect.height = vid.height - sb_lines;
vrect.pnext = 0;
SWVID_Update (&vrect);
}
else
{
vrect.x = scr_vrect.x;
vrect.y = scr_vrect.y;
vrect.width = scr_vrect.width;
vrect.height = scr_vrect.height;
vrect.pnext = 0;
SWVID_Update (&vrect);
}
}
/*
==================
SCR_UpdateWholeScreen
==================
*/
void SCR_UpdateWholeScreen (void)
{
scr_fullupdate = 0;
SCR_UpdateScreen ();
}
char *SWVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight)
{ //returns a BZ_Malloced array
qbyte *ret = BZ_Malloc(prepadbytes + vid.width*vid.height*3);
qbyte *dest, *src;
int y, x;
extern unsigned char vid_curpal[256*3];
if (r_pixbytes == 4)
{ //32 bit to 24
dest = ret+prepadbytes + vid.width*3*(vid.height-1);
for (y=0 ; y<vid.height ; y++, dest -= vid.width*3)
{
src = vid.buffer + y*vid.rowbytes*4;
for (x=0 ; x<vid.width*3 ; x+=3, src+=4)
{
dest[x] = src[2];
dest[x+1] = src[1];
dest[x+2] = src[0];
}
}
}
else
{ //8bit to 24 using palette lookups
dest = ret+prepadbytes + vid.width*3*(vid.height-1);
for (y=0 ; y<vid.height ; y++, dest -= vid.width*3)
{
src = vid.buffer + y*vid.rowbytes;
for (x=0 ; x<vid.width*3 ; x+=3, src++)
{
dest[x] = vid_curpal[*src*3];
dest[x+1] = vid_curpal[*src*3+1];
dest[x+2] = vid_curpal[*src*3+2];
}
}
}
*truewidth = vid.width;
*trueheight = vid.height;
return ret;
}

722
engine/sw/vid_ddraw.c Normal file
View file

@ -0,0 +1,722 @@
#include "quakedef.h"
#include "winquake.h"
qboolean vid_palettized;
#ifndef NODIRECTX
HMODULE hinstDDRAW;
LPDIRECTDRAW lpDirectDraw;
LPDIRECTDRAWSURFACE lpddsFrontBuffer, lpddsBackBuffer, lpddsOffScreenBuffer;
LPDIRECTDRAWPALETTE lpddpPalette;
extern qbyte vid_curpal[];
qboolean modex;
qboolean vid_initialized;
extern int redbits, redshift;
extern int greenbits, greenshift;
extern int bluebits, blueshift;
//end
static const char *DDrawError (int code);
/*
** DDRAW_SetPalette
**
** Sets the color table in our DIB section, and also sets the system palette
** into an identity mode if we're running in an 8-bit palettized display mode.
**
** The palette is expected to be 1024 bytes, in the format:
**
** R = offset 0
** G = offset 1
** B = offset 2
** A = offset 3
*/
void DDRAW_SetPalette( const unsigned char *pal )
{
static PALETTEENTRY palentries[256]; //does this help any drivers - being static?
int i;
if (!lpddpPalette)
return;
for ( i = 0; i < 256; i++, pal += 3 )
{
palentries[i].peRed = pal[0];
palentries[i].peGreen = pal[1];
palentries[i].peBlue = pal[2];
palentries[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE;
}
if ( lpddpPalette->lpVtbl->SetEntries( lpddpPalette,
0,
0,
256,
palentries ) != DD_OK )
{
Con_Printf( "DDRAW_SetPalette() - SetEntries failed\n" );
}
}
void DDRAW_Shutdown(void)
{
if ( lpddsOffScreenBuffer )
{
Con_SafePrintf( "...releasing offscreen buffer\n");
lpddsOffScreenBuffer->lpVtbl->Unlock( lpddsOffScreenBuffer, vid.buffer );
lpddsOffScreenBuffer->lpVtbl->Release( lpddsOffScreenBuffer );
lpddsOffScreenBuffer = NULL;
}
if ( lpddsBackBuffer )
{
Con_SafePrintf( "...releasing back buffer\n");
lpddsBackBuffer->lpVtbl->Release( lpddsBackBuffer );
lpddsBackBuffer = NULL;
}
if ( lpddsFrontBuffer )
{
Con_SafePrintf( "...releasing front buffer\n");
lpddsFrontBuffer->lpVtbl->Release( lpddsFrontBuffer );
lpddsFrontBuffer = NULL;
}
if ( lpddpPalette)
{
Con_SafePrintf( "...releasing palette\n");
lpddpPalette->lpVtbl->Release ( lpddpPalette );
lpddpPalette = NULL;
}
if ( lpDirectDraw )
{
Con_SafePrintf( "...restoring display mode\n");
lpDirectDraw->lpVtbl->RestoreDisplayMode( lpDirectDraw );
Con_SafePrintf( "...restoring normal coop mode\n");
lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw, mainwindow, DDSCL_NORMAL );
Con_SafePrintf( "...releasing lpDirectDraw\n");
lpDirectDraw->lpVtbl->Release( lpDirectDraw );
lpDirectDraw = NULL;
}
if ( hinstDDRAW )
{
Con_SafePrintf( "...freeing library\n");
FreeLibrary( hinstDDRAW );
hinstDDRAW = NULL;
}
}
unsigned short LowBitPos(DWORD dword)
{
int i;
for (i = 0; ; i++)
{
if (dword & (1<<i))
return i;
}
return 32;
}
unsigned short HighBitPos(DWORD dword)
{
int i;
for (i = LowBitPos(dword); ; i++)
{
if (!(dword & (1<<i)))
return i;
}
return 32;
}
qboolean DDRAW_Init(rendererstate_t *info, unsigned char **ppbuffer, int *ppitch )
{
int i;
PALETTEENTRY palentries[256];
DDSURFACEDESC ddsd;
DDSCAPS ddscaps;
HRESULT ddrval;
HRESULT (WINAPI *QDirectDrawCreate)( GUID FAR *lpGUID, LPDIRECTDRAW FAR * lplpDDRAW, IUnknown FAR * pUnkOuter );
hinstDDRAW = LoadLibrary( "ddraw.dll" );
if (!hinstDDRAW)
{
Con_Printf( "Failed to load ddraw.dll");
goto fail;
}
if ( ( QDirectDrawCreate = ( HRESULT (WINAPI *)( GUID FAR *, LPDIRECTDRAW FAR *, IUnknown FAR * ) ) GetProcAddress( hinstDDRAW, "DirectDrawCreate" ) ) == NULL )
{
Con_Printf( "*** DirectDrawCreate == NULL ***\n" );
goto fail;
}
if ( ( ddrval = QDirectDrawCreate( NULL, &lpDirectDraw, NULL ) ) != DD_OK )
{
Con_Printf( "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
#if 1
/*
** see if linear modes exist first
*/
modex = false;
Con_SafePrintf( "...setting exclusive mode: ");
if ( ( ddrval = lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw,
mainwindow,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n",DDrawError (ddrval) );
goto fail;
}
Con_SafePrintf( "ok\n" );
/*
** try changing the display mode normally
*/
Con_SafePrintf( "...finding display mode\n" );
Con_SafePrintf( "...setting linear mode: " );
if ( ( ddrval = lpDirectDraw->lpVtbl->SetDisplayMode( lpDirectDraw, vid.width, vid.height, r_pixbytes*8 ) ) == DD_OK )
{
Con_SafePrintf( "ok\n" );
}
/*
** if no linear mode found, go for modex if we're trying 320x240
*/
else if ( ( vid.width==320 && vid.height==240 ) && info->allow_modex )
{
Con_SafePrintf( "failed\n" );
Con_SafePrintf( "...attempting ModeX 320x240: ");
/*
** reset to normal cooperative level
*/
lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw,
mainwindow,
DDSCL_NORMAL );
/*
** set exclusive mode
*/
if ( ( ddrval = lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw,
mainwindow,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES | DDSCL_ALLOWMODEX | DDSCL_ALLOWREBOOT) ) != DD_OK )
{
Con_SafePrintf( "failed SCL - %s\n",DDrawError (ddrval) );
goto fail;
}
/*
** change our display mode
*/
if ( ( ddrval = lpDirectDraw->lpVtbl->SetDisplayMode( lpDirectDraw, vid.width, vid.height, r_pixbytes*8 ) ) != DD_OK )
{
Con_SafePrintf( "failed SDM - %s\n", DDrawError( ddrval ) );
goto fail;
}
Con_SafePrintf( "ok\n" );
modex = true;
}
else
{
Con_SafePrintf( "failed\n" );
goto fail;
}
/*
** create our front buffer
*/
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
Con_SafePrintf( "...creating front buffer: ");
if ( ( ddrval = lpDirectDraw->lpVtbl->CreateSurface( lpDirectDraw, &ddsd, &lpddsFrontBuffer, NULL ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
Con_SafePrintf( "ok\n" );
#else
Con_SafePrintf( "...setting normal mode: ");
if ( ( ddrval = lpDirectDraw->lpVtbl->SetCooperativeLevel( lpDirectDraw,
mainwindow,
DDSCL_NORMAL ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n",DDrawError (ddrval) );
goto fail;
}
Con_SafePrintf( "ok\n" );
i = r_pixbytes;
if (vid_use32bit.value)
r_pixbytes = 4;
else
r_pixbytes = 1;
if (r_pixbytes != i && cls.state)
{
Con_Printf("Cannot change bpp when connected\n");
r_pixbytes = i;
}
/*
** try changing the display mode
*/
/* if ( ( ddrval = lpDirectDraw->lpVtbl->SetDisplayMode( lpDirectDraw, vid.width, vid.height, r_pixbytes*8 ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n",DDrawError (ddrval) );
goto fail;
}
Con_SafePrintf( "ok\n" );
*/
/*
** create our front buffer
*/
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = /*DDSD_CAPS |*/ DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
Con_SafePrintf( "...creating front buffer: ");
if ( ( ddrval = lpDirectDraw->lpVtbl->CreateSurface( lpDirectDraw, &ddsd, &lpddsFrontBuffer, NULL ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
Con_SafePrintf( "ok\n" );
#endif
/*
** see if we're a ModeX mode
*/
lpddsFrontBuffer->lpVtbl->GetCaps( lpddsFrontBuffer, &ddscaps );
if ( ddscaps.dwCaps & DDSCAPS_MODEX )
Con_SafePrintf( "...using ModeX\n" );
/*
** create our back buffer
*/
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
Con_SafePrintf( "...creating back buffer: " );
if ( ( ddrval = lpddsFrontBuffer->lpVtbl->GetAttachedSurface( lpddsFrontBuffer, &ddsd.ddsCaps, &lpddsBackBuffer ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
Con_SafePrintf( "ok\n" );
/*
** create our rendering buffer
*/
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.dwHeight = vid.height;
ddsd.dwWidth = vid.width;
ddsd.dwRefreshRate = info->rate;
if (ddsd.dwRefreshRate)
ddsd.dwFlags |= DDSD_REFRESHRATE;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
Con_SafePrintf( "...creating offscreen buffer: " );
if ( ( ddrval = lpDirectDraw->lpVtbl->CreateSurface( lpDirectDraw, &ddsd, &lpddsOffScreenBuffer, NULL ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
Con_SafePrintf( "ok\n" );
if (r_pixbytes == 1)
{
/*
** create our DIRECTDRAWPALETTE
*/
Con_SafePrintf( "...creating palette: " );
if ( ( ddrval = lpDirectDraw->lpVtbl->CreatePalette( lpDirectDraw,
DDPCAPS_8BIT | DDPCAPS_ALLOW256,
palentries,
&lpddpPalette,
NULL ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
Con_SafePrintf( "ok\n" );
Con_SafePrintf( "...setting palette: " );
if ( ( ddrval = lpddsFrontBuffer->lpVtbl->SetPalette( lpddsFrontBuffer,
lpddpPalette ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
Con_SafePrintf( "ok\n" );
DDRAW_SetPalette( ( const unsigned char * ) vid_curpal );
vid_palettized = true;
}
/*
** lock the back buffer
*/
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
Con_SafePrintf( "...locking backbuffer: " );
if ( ( ddrval = lpddsOffScreenBuffer->lpVtbl->Lock( lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL ) ) != DD_OK )
{
Con_SafePrintf( "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
Con_SafePrintf( "ok\n" );
if (r_pixbytes == 2)
{
DDPIXELFORMAT format;
format.dwSize = sizeof(format);
Con_SafePrintf( "...getting pixel format: " );
if (lpddsFrontBuffer->lpVtbl->GetPixelFormat(lpddsFrontBuffer, &format) == DD_OK)
{
int hi, lo;
lo = LowBitPos(format.dwRBitMask);
hi = HighBitPos(format.dwRBitMask);
Con_SafePrintf("Hi=%i, Low=%i\n", hi, lo);
redshift = lo;
redbits = hi-lo;
lo = LowBitPos(format.dwGBitMask);
hi = HighBitPos(format.dwGBitMask);
Con_SafePrintf("Hi=%i, Low=%i\n", hi, lo);
greenshift = lo;
greenbits = hi-lo;
lo = LowBitPos(format.dwBBitMask);
hi = HighBitPos(format.dwBBitMask);
Con_SafePrintf("Hi=%i, Low=%i\n", hi, lo);
blueshift = lo;
bluebits = hi-lo;
}
else
{
Con_SafePrintf( "failed\n" );
goto fail;
}
Con_SafePrintf( "ok\n" );
}
*ppbuffer = ddsd.lpSurface;
*ppitch = ddsd.lPitch/r_pixbytes;
for ( i = 0; i < vid.height; i++ )
{
memset( *ppbuffer + i * *ppitch, 0, *ppitch );
}
return true;
fail:
Con_SafePrintf( "*** DDraw init failure ***\n" );
DDRAW_Shutdown();
return false;
}
static const char *DDrawError (int code)
{
switch(code) {
case DD_OK:
return "DD_OK";
case DDERR_ALREADYINITIALIZED:
return "DDERR_ALREADYINITIALIZED";
case DDERR_BLTFASTCANTCLIP:
return "DDERR_BLTFASTCANTCLIP";
case DDERR_CANNOTATTACHSURFACE:
return "DDER_CANNOTATTACHSURFACE";
case DDERR_CANNOTDETACHSURFACE:
return "DDERR_CANNOTDETACHSURFACE";
case DDERR_CANTCREATEDC:
return "DDERR_CANTCREATEDC";
case DDERR_CANTDUPLICATE:
return "DDER_CANTDUPLICATE";
case DDERR_CLIPPERISUSINGHWND:
return "DDER_CLIPPERUSINGHWND";
case DDERR_COLORKEYNOTSET:
return "DDERR_COLORKEYNOTSET";
case DDERR_CURRENTLYNOTAVAIL:
return "DDERR_CURRENTLYNOTAVAIL";
case DDERR_DIRECTDRAWALREADYCREATED:
return "DDERR_DIRECTDRAWALREADYCREATED";
case DDERR_EXCEPTION:
return "DDERR_EXCEPTION";
case DDERR_EXCLUSIVEMODEALREADYSET:
return "DDERR_EXCLUSIVEMODEALREADYSET";
case DDERR_GENERIC:
return "DDERR_GENERIC";
case DDERR_HEIGHTALIGN:
return "DDERR_HEIGHTALIGN";
case DDERR_HWNDALREADYSET:
return "DDERR_HWNDALREADYSET";
case DDERR_HWNDSUBCLASSED:
return "DDERR_HWNDSUBCLASSED";
case DDERR_IMPLICITLYCREATED:
return "DDERR_IMPLICITLYCREATED";
case DDERR_INCOMPATIBLEPRIMARY:
return "DDERR_INCOMPATIBLEPRIMARY";
case DDERR_INVALIDCAPS:
return "DDERR_INVALIDCAPS";
case DDERR_INVALIDCLIPLIST:
return "DDERR_INVALIDCLIPLIST";
case DDERR_INVALIDDIRECTDRAWGUID:
return "DDERR_INVALIDDIRECTDRAWGUID";
case DDERR_INVALIDMODE:
return "DDERR_INVALIDMODE";
case DDERR_INVALIDOBJECT:
return "DDERR_INVALIDOBJECT";
case DDERR_INVALIDPARAMS:
return "DDERR_INVALIDPARAMS";
case DDERR_INVALIDPIXELFORMAT:
return "DDERR_INVALIDPIXELFORMAT";
case DDERR_INVALIDPOSITION:
return "DDERR_INVALIDPOSITION";
case DDERR_INVALIDRECT:
return "DDERR_INVALIDRECT";
case DDERR_LOCKEDSURFACES:
return "DDERR_LOCKEDSURFACES";
case DDERR_NO3D:
return "DDERR_NO3D";
case DDERR_NOALPHAHW:
return "DDERR_NOALPHAHW";
case DDERR_NOBLTHW:
return "DDERR_NOBLTHW";
case DDERR_NOCLIPLIST:
return "DDERR_NOCLIPLIST";
case DDERR_NOCLIPPERATTACHED:
return "DDERR_NOCLIPPERATTACHED";
case DDERR_NOCOLORCONVHW:
return "DDERR_NOCOLORCONVHW";
case DDERR_NOCOLORKEY:
return "DDERR_NOCOLORKEY";
case DDERR_NOCOLORKEYHW:
return "DDERR_NOCOLORKEYHW";
case DDERR_NOCOOPERATIVELEVELSET:
return "DDERR_NOCOOPERATIVELEVELSET";
case DDERR_NODC:
return "DDERR_NODC";
case DDERR_NODDROPSHW:
return "DDERR_NODDROPSHW";
case DDERR_NODIRECTDRAWHW:
return "DDERR_NODIRECTDRAWHW";
case DDERR_NOEMULATION:
return "DDERR_NOEMULATION";
case DDERR_NOEXCLUSIVEMODE:
return "DDERR_NOEXCLUSIVEMODE";
case DDERR_NOFLIPHW:
return "DDERR_NOFLIPHW";
case DDERR_NOGDI:
return "DDERR_NOGDI";
case DDERR_NOHWND:
return "DDERR_NOHWND";
case DDERR_NOMIRRORHW:
return "DDERR_NOMIRRORHW";
case DDERR_NOOVERLAYDEST:
return "DDERR_NOOVERLAYDEST";
case DDERR_NOOVERLAYHW:
return "DDERR_NOOVERLAYHW";
case DDERR_NOPALETTEATTACHED:
return "DDERR_NOPALETTEATTACHED";
case DDERR_NOPALETTEHW:
return "DDERR_NOPALETTEHW";
case DDERR_NORASTEROPHW:
return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0";
case DDERR_NOROTATIONHW:
return "Operation could not be carried out because there is no rotation hardware present or available.\0";
case DDERR_NOSTRETCHHW:
return "Operation could not be carried out because there is no hardware support for stretching.\0";
case DDERR_NOT4BITCOLOR:
return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0";
case DDERR_NOT4BITCOLORINDEX:
return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0";
case DDERR_NOT8BITCOLOR:
return "DDERR_NOT8BITCOLOR";
case DDERR_NOTAOVERLAYSURFACE:
return "Returned when an overlay member is called for a non-overlay surface.\0";
case DDERR_NOTEXTUREHW:
return "Operation could not be carried out because there is no texture mapping hardware present or available.\0";
case DDERR_NOTFLIPPABLE:
return "DDERR_NOTFLIPPABLE";
case DDERR_NOTFOUND:
return "DDERR_NOTFOUND";
case DDERR_NOTLOCKED:
return "DDERR_NOTLOCKED";
case DDERR_NOTPALETTIZED:
return "DDERR_NOTPALETTIZED";
case DDERR_NOVSYNCHW:
return "DDERR_NOVSYNCHW";
case DDERR_NOZBUFFERHW:
return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0";
case DDERR_NOZOVERLAYHW:
return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0";
case DDERR_OUTOFCAPS:
return "The hardware needed for the requested operation has already been allocated.\0";
case DDERR_OUTOFMEMORY:
return "DDERR_OUTOFMEMORY";
case DDERR_OUTOFVIDEOMEMORY:
return "DDERR_OUTOFVIDEOMEMORY";
case DDERR_OVERLAYCANTCLIP:
return "The hardware does not support clipped overlays.\0";
case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
return "Can only have ony color key active at one time for overlays.\0";
case DDERR_OVERLAYNOTVISIBLE:
return "Returned when GetOverlayPosition is called on a hidden overlay.\0";
case DDERR_PALETTEBUSY:
return "DDERR_PALETTEBUSY";
case DDERR_PRIMARYSURFACEALREADYEXISTS:
return "DDERR_PRIMARYSURFACEALREADYEXISTS";
case DDERR_REGIONTOOSMALL:
return "Region passed to Clipper::GetClipList is too small.\0";
case DDERR_SURFACEALREADYATTACHED:
return "DDERR_SURFACEALREADYATTACHED";
case DDERR_SURFACEALREADYDEPENDENT:
return "DDERR_SURFACEALREADYDEPENDENT";
case DDERR_SURFACEBUSY:
return "DDERR_SURFACEBUSY";
case DDERR_SURFACEISOBSCURED:
return "Access to surface refused because the surface is obscured.\0";
case DDERR_SURFACELOST:
return "DDERR_SURFACELOST";
case DDERR_SURFACENOTATTACHED:
return "DDERR_SURFACENOTATTACHED";
case DDERR_TOOBIGHEIGHT:
return "Height requested by DirectDraw is too large.\0";
case DDERR_TOOBIGSIZE:
return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0";
case DDERR_TOOBIGWIDTH:
return "Width requested by DirectDraw is too large.\0";
case DDERR_UNSUPPORTED:
return "DDERR_UNSUPPORTED";
case DDERR_UNSUPPORTEDFORMAT:
return "FOURCC format requested is unsupported by DirectDraw.\0";
case DDERR_UNSUPPORTEDMASK:
return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0";
case DDERR_VERTICALBLANKINPROGRESS:
return "Vertical blank is in progress.\0";
case DDERR_WASSTILLDRAWING:
return "DDERR_WASSTILLDRAWING";
case DDERR_WRONGMODE:
return "This surface can not be restored because it was created in a different mode.\0";
case DDERR_XALIGN:
return "Rectangle provided was not horizontally aligned on required boundary.\0";
default:
return "UNKNOWN\0";
}
}
void DDRAW_SwapBuffers (void)
{
RECT r;
HRESULT rval;
DDSURFACEDESC ddsd;
r.left = 0;
r.top = 0;
r.right = vid.width;
r.bottom = vid.height;
lpddsOffScreenBuffer->lpVtbl->Unlock( lpddsOffScreenBuffer, vid.buffer );
if ( modex )
{
if ( ( rval = lpddsBackBuffer->lpVtbl->BltFast( lpddsBackBuffer,
0, 0,
lpddsOffScreenBuffer,
&r,
DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST )
{
lpddsBackBuffer->lpVtbl->Restore( lpddsBackBuffer );
lpddsBackBuffer->lpVtbl->BltFast( lpddsBackBuffer,
0, 0,
lpddsOffScreenBuffer,
&r,
DDBLTFAST_WAIT );
Con_DPrintf("surface lost\n");
}
if ( ( rval = lpddsFrontBuffer->lpVtbl->Flip( lpddsFrontBuffer,
NULL, DDFLIP_WAIT ) ) == DDERR_SURFACELOST )
{
lpddsFrontBuffer->lpVtbl->Restore( lpddsFrontBuffer );
lpddsFrontBuffer->lpVtbl->Flip( lpddsFrontBuffer, NULL, DDFLIP_WAIT );
}
}
else
{
if ( ( rval = lpddsBackBuffer->lpVtbl->BltFast( lpddsFrontBuffer,
0, 0,
lpddsOffScreenBuffer,
&r,
DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST )
{
lpddsBackBuffer->lpVtbl->Restore( lpddsFrontBuffer );
lpddsBackBuffer->lpVtbl->BltFast( lpddsFrontBuffer,
0, 0,
lpddsOffScreenBuffer,
&r,
DDBLTFAST_WAIT );
Con_DPrintf("surface lost\n");
}
}
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
if (lpddsOffScreenBuffer->lpVtbl->Lock( lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL ))
Sys_Error("Failed to lock ddraw");
vid.conbuffer = vid.buffer = ddsd.lpSurface;
vid.conrowbytes = vid.rowbytes = ddsd.lPitch/r_pixbytes;
}
#else
qboolean DDRAW_Init(rendererstate_t *info, unsigned char **ppbuffer, int *ppitch )
{
return false;
}
void DDRAW_SwapBuffers (void)
{
}
void DDRAW_Shutdown(void)
{
}
void DDRAW_SetPalette( const unsigned char *pal )
{
}
#endif

412
engine/sw/vid_dib.c Normal file
View file

@ -0,0 +1,412 @@
/*
** This handles DIB section management under Windows.
*/
#include "quakedef.h"
#include "winquake.h"
#include "r_local.h"
void DIB_Shutdown( void );
#ifndef _WIN32
# error You should not be trying to compile this file on this platform
#endif
HDC mainhDC, hdcDIBSection;
HBITMAP hDIBSection;
HPALETTE hPal, hpalOld;
qbyte *pDIBBase;
extern qboolean vid_palettized;
extern cvar_t vid_use32bit;
static qboolean s_systemcolors_saved;
extern int redbits, redshift;
extern int greenbits, greenshift;
extern int bluebits, blueshift;
static HGDIOBJ previously_selected_GDI_obj;
static int s_syspalindices[] =
{
COLOR_ACTIVEBORDER,
COLOR_ACTIVECAPTION,
COLOR_APPWORKSPACE,
COLOR_BACKGROUND,
COLOR_BTNFACE,
COLOR_BTNSHADOW,
COLOR_BTNTEXT,
COLOR_CAPTIONTEXT,
COLOR_GRAYTEXT,
COLOR_HIGHLIGHT,
COLOR_HIGHLIGHTTEXT,
COLOR_INACTIVEBORDER,
COLOR_INACTIVECAPTION,
COLOR_MENU,
COLOR_MENUTEXT,
COLOR_SCROLLBAR,
COLOR_WINDOW,
COLOR_WINDOWFRAME,
COLOR_WINDOWTEXT
};
#define NUM_SYS_COLORS ( sizeof( s_syspalindices ) / sizeof( int ) )
static COLORREF s_oldsyscolors[NUM_SYS_COLORS];
typedef struct dibinfo
{
BITMAPINFOHEADER header;
RGBQUAD acolors[256];
} dibinfo_t;
typedef struct
{
WORD palVersion;
WORD palNumEntries;
PALETTEENTRY palEntries[256];
} identitypalette_t;
static identitypalette_t s_ipal;
static void DIB_SaveSystemColors( void );
static void DIB_RestoreSystemColors( void );
/*
** DIB_Init
**
** Builds our DIB section
*/
qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch )
{
dibinfo_t dibheader;
BITMAPINFO *pbmiDIB = ( BITMAPINFO * ) &dibheader;
int i;
memset( &dibheader, 0, sizeof( dibheader ) );
/*
** grab a DC
*/
if ( !mainhDC )
{
if ( ( mainhDC = GetDC( mainwindow ) ) == NULL )
return false;
}
/*
** figure out if we're running in an 8-bit display mode
*/
if ( GetDeviceCaps( mainhDC, RASTERCAPS ) & RC_PALETTE )
{
vid_palettized = true;
// save system colors
if ( !s_systemcolors_saved )
{
DIB_SaveSystemColors();
s_systemcolors_saved = true;
}
}
else
{
vid_palettized = false;
}
/*
** fill in the BITMAPINFO struct
*/
pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmiDIB->bmiHeader.biWidth = vid.width;
pbmiDIB->bmiHeader.biHeight = vid.height;
pbmiDIB->bmiHeader.biPlanes = 1;
pbmiDIB->bmiHeader.biBitCount = r_pixbytes*8;
pbmiDIB->bmiHeader.biCompression = BI_RGB;
pbmiDIB->bmiHeader.biSizeImage = 0;
pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
pbmiDIB->bmiHeader.biClrUsed = 0;
pbmiDIB->bmiHeader.biClrImportant = 0;
/*
** fill in the palette
*/
for ( i = 0; i < 256; i++ )
{
dibheader.acolors[i].rgbRed = ( d_8to24rgbtable[i] >> 0 ) & 0xff;
dibheader.acolors[i].rgbGreen = ( d_8to24rgbtable[i] >> 8 ) & 0xff;
dibheader.acolors[i].rgbBlue = ( d_8to24rgbtable[i] >> 16 ) & 0xff;
}
/*
** create the DIB section
*/
hDIBSection = CreateDIBSection( mainhDC,
pbmiDIB,
DIB_RGB_COLORS,
(void**)&pDIBBase,
NULL,
0 );
if ( hDIBSection == NULL )
{
Con_Printf( "DIB_Init() - CreateDIBSection failed\n" );
goto fail;
}
if ( pbmiDIB->bmiHeader.biHeight > 0 )
{
// bottom up
*ppbuffer = pDIBBase + ( vid.height - 1 ) * vid.width * r_pixbytes;
*ppitch = -(int)vid.width;
}
else
{
// top down
*ppbuffer = pDIBBase;
*ppitch = vid.width;
}
/*
** clear the DIB memory buffer
*/
memset( pDIBBase, 0xff, vid.width * vid.height * r_pixbytes);
if ( ( hdcDIBSection = CreateCompatibleDC( mainhDC ) ) == NULL )
{
Con_Printf( "DIB_Init() - CreateCompatibleDC failed\n" );
goto fail;
}
if ( ( previously_selected_GDI_obj = SelectObject( hdcDIBSection, hDIBSection ) ) == NULL )
{
Con_Printf( "DIB_Init() - SelectObject failed\n" );
goto fail;
}
redbits = 5; redshift=10;
greenbits = 5; greenshift=5;
bluebits = 5; blueshift=0;
return true;
fail:
DIB_Shutdown();
return false;
}
void DIB_Resized(void)
{
}
/*
** DIB_SetPalette
**
** Sets the color table in our DIB section, and also sets the system palette
** into an identity mode if we're running in an 8-bit palettized display mode.
**
** The palette is expected to be 1024 bytes, in the format:
**
** R = offset 0
** G = offset 1
** B = offset 2
** A = offset 3
*/
void DIB_SetPalette( const unsigned char *_pal )
{
const unsigned char *pal = _pal;
LOGPALETTE *pLogPal = ( LOGPALETTE * ) &s_ipal;
RGBQUAD colors[256];
int i;
int ret;
HDC hDC = mainhDC;
/*
** set the DIB color table
*/
if (r_pixbytes == 1 && hdcDIBSection )
{
for ( i = 0; i < 256; i++, pal += 3 )
{
colors[i].rgbRed = pal[0];
colors[i].rgbGreen = pal[1];
colors[i].rgbBlue = pal[2];
colors[i].rgbReserved = 0;
}
colors[0].rgbRed = 0;
colors[0].rgbGreen = 0;
colors[0].rgbBlue = 0;
colors[255].rgbRed = 0xff;
colors[255].rgbGreen = 0xff;
colors[255].rgbBlue = 0xff;
if ( SetDIBColorTable( hdcDIBSection, 0, 256, colors ) == 0 )
{
Con_Printf( "DIB_SetPalette() - SetDIBColorTable failed\n" );
}
}
/*
** for 8-bit color desktop modes we set up the palette for maximum
** speed by going into an identity palette mode.
*/
if ( vid_palettized )
{
int i;
HPALETTE hpalOld;
if ( SetSystemPaletteUse( hDC, SYSPAL_NOSTATIC ) == SYSPAL_ERROR )
{
Sys_Error( "DIB_SetPalette() - SetSystemPaletteUse() failed\n" );
}
/*
** destroy our old palette
*/
if ( hPal )
{
DeleteObject( hPal );
hPal = 0;
}
/*
** take up all physical palette entries to flush out anything that's currently
** in the palette
*/
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = 256;
for ( i = 0, pal = _pal; i < 256; i++, pal += 3 )
{
pLogPal->palPalEntry[i].peRed = pal[0];
pLogPal->palPalEntry[i].peGreen = pal[1];
pLogPal->palPalEntry[i].peBlue = pal[2];
pLogPal->palPalEntry[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE;
}
pLogPal->palPalEntry[0].peRed = 0;
pLogPal->palPalEntry[0].peGreen = 0;
pLogPal->palPalEntry[0].peBlue = 0;
pLogPal->palPalEntry[0].peFlags = 0;
pLogPal->palPalEntry[255].peRed = 0xff;
pLogPal->palPalEntry[255].peGreen = 0xff;
pLogPal->palPalEntry[255].peBlue = 0xff;
pLogPal->palPalEntry[255].peFlags = 0;
if ( ( hPal = CreatePalette( pLogPal ) ) == NULL )
{
Sys_Error( "DIB_SetPalette() - CreatePalette failed(%x)\n", GetLastError() );
}
if ( ( hpalOld = SelectPalette( hDC, hPal, FALSE ) ) == NULL )
{
Sys_Error( "DIB_SetPalette() - SelectPalette failed(%x)\n",GetLastError() );
}
if ( hpalOld == NULL )
hpalOld = hpalOld;
if ( ( ret = RealizePalette( hDC ) ) != pLogPal->palNumEntries )
{
Sys_Error( "DIB_SetPalette() - RealizePalette set %d entries\n", ret );
}
}
}
/*
** DIB_Shutdown
*/
void DIB_Shutdown( void )
{
if ( vid_palettized && s_systemcolors_saved )
DIB_RestoreSystemColors();
if ( hPal )
{
DeleteObject( hPal );
hPal = NULL;
}
if ( hpalOld )
{
SelectPalette( mainhDC, hpalOld, FALSE );
RealizePalette( mainhDC );
hpalOld = NULL;
}
if ( hdcDIBSection )
{
SelectObject( hdcDIBSection, previously_selected_GDI_obj );
DeleteDC( hdcDIBSection );
hdcDIBSection = NULL;
}
if ( hDIBSection )
{
DeleteObject( hDIBSection );
hDIBSection = NULL;
pDIBBase = NULL;
}
if ( mainhDC )
{
ReleaseDC( mainwindow, mainhDC );
mainhDC = 0;
}
}
/*
** DIB_Save/RestoreSystemColors
*/
static void DIB_RestoreSystemColors( void )
{
SetSystemPaletteUse( mainhDC, SYSPAL_STATIC );
SetSysColors( NUM_SYS_COLORS, s_syspalindices, s_oldsyscolors );
}
static void DIB_SaveSystemColors( void )
{
int i;
for ( i = 0; i < NUM_SYS_COLORS; i++ )
s_oldsyscolors[i] = GetSysColor( s_syspalindices[i] );
}
void DIB_SwapBuffers(void)
{
extern float usingstretch;
if ( vid_palettized )
{
// holdpal = SelectPalette(hdcScreen, hpalDIB, FALSE);
// RealizePalette(hdcScreen);
}
if (usingstretch == 1)
BitBlt( mainhDC,
0, 0,
vid.width,
vid.height,
hdcDIBSection,
0, 0,
SRCCOPY );
else
StretchBlt( mainhDC, //Why is StretchBlt not optimised for a scale of 2? Surly that would be a frequently used quantity?
0, 0,
vid.width*usingstretch,
vid.height*usingstretch,
hdcDIBSection,
0, 0,
vid.width, vid.height,
SRCCOPY );
if ( vid_palettized )
{
// SelectPalette(hdcScreen, holdpal, FALSE);
}
}

1066
engine/sw/vid_win2.c Normal file

File diff suppressed because it is too large Load diff