CTR: Initial Import

This commit is contained in:
cypress 2024-09-08 18:10:06 -07:00
parent 835c932566
commit 8cc00c95a2
61 changed files with 30621 additions and 79 deletions

118
.github/workflows/build-and-release.yml vendored Normal file
View file

@ -0,0 +1,118 @@
name: Build EBOOT and Publish Release
on: [push]
jobs:
Compile-EBOOT:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
container:
image: pspdev/pspdev
steps:
- uses: actions/checkout@v2
- name: Get container ready
run: |
apk add bash zip git gmp mpc1 mpfr4 make
- name: Build
working-directory: ./
run: |
cd source/psp/libpspmath
make && make install
cd ../../../
make -f Makefile.psp install
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: psp-nzp-eboot
path: ./build/psp/bin/EBOOT.PBP
Compile-3DSX:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
outputs:
o3ds_link: ${{ steps.zip.outputs.zip }}
container:
image: devkitpro/devkitarm
steps:
- uses: actions/checkout@v2
- name: Install Packages and update picaGL
run: |
git clone https://github.com/masterfeizz/picaGL.git
cd picaGL
git checkout revamp
mkdir clean
make install
- name: Build
working-directory: ./
run: |
make -f Makefile.ctr
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: ctr-nzp-3dsx
path: ./build/3ds/bin/nzportable.3dsx
Unify-and-Release:
runs-on: ubuntu-latest
needs: [Compile-EBOOT, Compile-3DSX]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Wait for GitHub to keep up..
run: sleep 2s
shell: bash
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: ./
- name: Turn Artifacts into .ZIP archives
run: |
zip -r -j psp-nzp-eboot.zip psp-nzp-eboot/*
zip -r -j ctr-nzp-3dsx.zip ctr-nzp-3dsx/*
- name: Generate Build Date
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d-%H-%M-%S')"
- name: Delete Old Release
uses: dev-drprasad/delete-tag-and-release@v0.2.1
with:
delete_release: true
tag_name: bleeding-edge
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: bleeding-edge
release_name: Automated Release ${{ steps.date.outputs.date }}
body: |
This is a **bleeding edge** NZ:P NX/VITA release, stability is not guarenteed.
To install:
- Grab the .ZIP archive for your platform
- PSP: Extract the `EBOOT.PBP` to `/PSP/GAME/nzportable/`
- 3DS: Extract `nzportable.3dsx` to `/3ds/nzportable/`.
draft: true
prerelease: false
- name: Upload PSP Archive
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./psp-nzp-eboot.zip
asset_name: psp-nzp-eboot.zip
asset_content_type: application/zip
- name: Upload 3DS Archive
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./ctr-nzp-3dsx.zip
asset_name: ctr-nzp-3dsx.zip
asset_content_type: application/zip
- name: Publish Release
uses: StuYarrow/publish-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
id: ${{ steps.create_release.outputs.id }}

View file

@ -1,66 +0,0 @@
name: Build EBOOT and Publish Release
on: [push]
jobs:
Compile-EBOOT:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
container:
image: pspdev/pspdev
steps:
- uses: actions/checkout@v2
- name: Get container ready
run: |
apk add bash zip git gmp mpc1 mpfr4 make
- name: Build
working-directory: ./
run: |
cd source/psp/libpspmath
make && make install
cd ../../../
make -f Makefile.psp install
- name: Generate Build Date
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d-%H-%M-%S')"
- name: Zip EBOOT
working-directory: ./build
run: |
zip -r -j psp-nzp-eboot.zip build/psp/bin/EBOOT.PBP
- name: Delete Old Release
uses: dev-drprasad/delete-tag-and-release@v0.2.1
with:
delete_release: true
tag_name: bleeding-edge
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: bleeding-edge
release_name: Automated Release ${{ steps.date.outputs.date }}
body: |
This is a **bleeding edge** NZ:P PSP EBOOT release, stability is not guarenteed.
To install:
- Grab the .ZIP archive (psp-nzp-eboot.zip)
- Extract the contents of the .ZIP archive to `PSP/GAME/nzportable`.
draft: true
prerelease: false
- name: Upload EBOOT Archive
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./build/psp-nzp-eboot.zip
asset_name: psp-nzp-eboot.zip
asset_content_type: application/zip
- name: Publish Release
uses: StuYarrow/publish-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
id: ${{ steps.create_release.outputs.id }}

265
Makefile.ctr Normal file
View file

@ -0,0 +1,265 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/3ds_rules
TARGET := nzportable
BUILD := build
SOURCES := source
#DATA := data
INCLUDES := include
ICON := source/ctr/art/icon.png
#ROMFS := romfs
APP_AUTHOR := NZ:P Team
APP_TITLE := Nazi Zombies: Portable
APP_DESCRIPTION := Call of Duty Zombies remake
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -g -fpermissive -Wall -O3 -mword-relocations \
-fomit-frame-pointer -ffunction-sections \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DGLQUAKE
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lpicaGL -lctru -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB) $(DEVKITPRO)/picaGL
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
COMMON_OBJS = chase.c \
cl_hud.c \
cl_demo.c \
cl_input.c \
cl_main.c \
cl_parse.c \
cl_tent.c \
cl_slist.c \
ctr/bsp_strlcpy.c \
cmd.c \
ctr/common.c \
console.c \
crc.c \
cvar.c \
host.c \
host_cmd.c \
ctr/keys.c \
mathlib.c \
matrixlib.c \
ctr/menu.c \
ctr/net_dgrm.c \
ctr/net_udpctr.c \
net_loop.c \
ctr/net_bsd.c \
ctr/net_main.c \
net_vcr.c \
pr_cmds.c \
pr_edict.c \
pr_exec.c \
ctr/sbar.c \
sv_main.c \
sv_move.c \
sv_phys.c \
sv_user.c \
view.c \
wad.c \
world.c \
zone.c \
ctr/sys_ctr.c \
snd_dma.c \
snd_mix.c \
snd_mem.c \
ctr/snd_ctr.c \
ctr/in_ctr.c \
ctr/cd_null.c \
ctr/gl/gl_qmb.c \
ctr/gl/gl_decal.c \
ctr/gl/gl_draw.c \
ctr/gl/gl_fog.c \
ctr/gl/gl_mesh.c \
ctr/gl/gl_model.c \
ctr/gl/gl_refrag.c \
ctr/gl/gl_rlight.c \
ctr/gl/gl_rmain.c \
ctr/gl/gl_rmisc.c \
ctr/gl/gl_rsurf.c \
ctr/gl/gl_screen.c \
ctr/gl/gl_warp.c \
ctr/gl/gl_vidctr.c \
ctr/r_part.c \
ctr/touch_ctr.c \
crypter.c
CFILES := $(COMMON_OBJS)
CPPFILES :=
SFILES :=
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
#BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES_BIN := $(addsuffix .o,$(BINFILES)) \
$(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o)
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)
export HFILES := $(PICAFILES:.v.pica=_shbin.h) $(SHLISTFILES:.shlist=_shbin.h) $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.png)
ifneq (,$(findstring $(TARGET).png,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).png
else
ifneq (,$(findstring icon.png,$(icons)))
export APP_ICON := $(TOPDIR)/icon.png
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
ifeq ($(strip $(NO_SMDH)),)
export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh
endif
ifneq ($(ROMFS),)
export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@mkdir -p $(BUILD)/ctr
@mkdir -p $(BUILD)/ctr/gl
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.ctr
@mkdir -p $(BUILD)/3ds
@mkdir -p $(BUILD)/3ds/bin/
@mv $(BUILD)/*.o $(BUILD)/3ds/
@mv $(BUILD)/*.d $(BUILD)/3ds/
@mv $(BUILD)/ctr $(BUILD)/3ds/
@mv $(BUILD)/$(TARGET).lst $(BUILD)/3ds/
@mv $(BUILD)/$(TARGET).map $(BUILD)/3ds/
@mv $(TARGET).* $(BUILD)/3ds/bin/
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD)
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(NO_SMDH)),)
$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh
else
$(OUTPUT).3dsx : $(OUTPUT).elf
endif
$(OFILES_SOURCES) : $(HFILES)
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
# rules for assembling GPU shaders
#---------------------------------------------------------------------------------
define shader-as
$(eval CURBIN := $*.shbin)
$(eval DEPSFILE := $(DEPSDIR)/$*.shbin.d)
echo "$(CURBIN).o: $< $1" > $(DEPSFILE)
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h
picasso -o $(CURBIN) $1
bin2s $(CURBIN) | $(AS) -o $*.shbin.o
endef
%.shbin.o %_shbin.h : %.v.pica %.g.pica
@echo $(notdir $^)
@$(call shader-as,$^)
%.shbin.o %_shbin.h : %.v.pica
@echo $(notdir $<)
@$(call shader-as,$<)
%.shbin.o %_shbin.h : %.shlist
@echo $(notdir $<)
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)$(file)))
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -1,4 +1,4 @@
#MAKEFLAGS+="-j -l $(shell grep -c ^processor /proc/cpuinfo) "
MAKEFLAGS+="-j -l $(shell grep -c ^processor /proc/cpuinfo) "
PSPSDK = $(shell psp-config --pspsdk-path)
PSPLIBSDIR = $(PSPSDK)/..
@ -127,17 +127,13 @@ clean:
rm source/psp/*.o
rm source/*.o
clean-keep-eboot:
rm -rf build/exec/
rm source/psp/*.o
rm source/*.o
install: EBOOT.PBP
mkdir -p build/exec/
mv EBOOT.PBP build/
mkdir -p build/psp/
mkdir -p build/psp/bin
mv EBOOT.PBP build/psp/bin/
ifeq ($(DEBUG),1)
mv *.prx build/exec/
mv *.prx build/psp/
endif
mv *.elf build/exec/
mv *.SFO build/exec/
mv *.elf build/psp/
mv *.SFO build/psp/
@echo DONE

View file

@ -1,7 +1,7 @@
# Nazi Zombies: Portable dQuakePlus
## About
This repository contains the PSP engine for NZ:P, based on dQuakePlus and containing optimizations from the NZ:P Team, adQuake, and Xash3D-PSP, as well as NZ:P-specific feature implementation. It has also been modified to build on the latest versions of the [PSPSDK](https://github.com/pspdev/pspsdk).
This repository contains the PlayStation Portable and Nintendo 3DS engine for NZ:P, based on dQuakePlus and ctrQuake, containing optimizations from the NZ:P Team, adQuake, and Xash3D-PSP, as well as NZ:P-specific feature implementation. It has also been modified to build on the latest versions of the [PSPSDK](https://github.com/pspdev/pspsdk).
## Building for PlayStation Portable
Building requires a full install of [psptoolchain](https://github.com/pspdev/psptoolchain/). You can either follow the instructions on the GitHub repository or use a Docker container (we recommend [the official one](https://hub.docker.com/r/pspdev/pspdev))!
@ -19,3 +19,21 @@ make -f Makefile.psp install
```
We also provide a prebuilt EBOOT on the [Releases](https://github.com/nzp-team/dquakeplus/releases/tag/bleeding-edge) page.
## Building for Nintendo 3DS
Building requires a full install of [libctru](https://github.com/devkitPro/libctru). You can either follow the instructions on the GitHub repository or use a Docker container (we recommend [the official one](devkitpro/devkitarm))!
With the psptoolchain installed, you now need to install the latest `picaGL`, which needs cloned from the official GitHub repository:
```bash
git clone https://github.com/masterfeizz/picaGL.git -b revamp
cd picaGL
mkdir clean
make install
```
Now you can navigate to the root of the repository and build the `.3dsx`.
```bash
make -f Makefile.ctr
```
We also provide prebuilt .3dsx files on the [Releases](https://github.com/nzp-team/dquakeplus/releases/tag/bleeding-edge) page.

BIN
source/ctr/art/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
source/ctr/art/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

54
source/ctr/bsp_strlcpy.c Normal file
View file

@ -0,0 +1,54 @@
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include "strl_fn.h"
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
q_strlcpy (char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}

55
source/ctr/cd_null.c Normal file
View file

@ -0,0 +1,55 @@
/*
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.
*/
#include "../quakedef.h"
void CDAudio_Play(byte track, qboolean looping)
{
}
void CDAudio_Stop(void)
{
}
void CDAudio_Pause(void)
{
}
void CDAudio_Resume(void)
{
}
void CDAudio_Update(void)
{
}
int CDAudio_Init(void)
{
return 0;
}
void CDAudio_Shutdown(void)
{
}

425
source/ctr/client.h Normal file
View file

@ -0,0 +1,425 @@
/*
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.
*/
// client.h
typedef struct
{
vec3_t viewangles;
// intended velocities
float forwardmove;
float sidemove;
float upmove;
#ifdef QUAKE2
byte lightlevel;
#endif
} usercmd_t;
typedef struct
{
int length;
char map[MAX_STYLESTRING];
char average; //johnfitz
char peak; //johnfitz
} lightstyle_t;
typedef struct
{
char name[MAX_SCOREBOARDNAME];
float entertime;
int points;
int maxpoints;
int kills;
int headshots;
} scoreboard_t;
typedef struct
{
int destcolor[3];
int percent; // 0-256
} cshift_t;
typedef enum
{
lt_default, lt_muzzleflash, lt_explosion, lt_rocket,
lt_red, lt_blue, lt_redblue, lt_green, NUM_DLIGHTTYPES,
lt_explosion2, lt_explosion3, lt_rayred, lt_raygreen
} dlighttype_t;
#define CSHIFT_CONTENTS 0
#define CSHIFT_DAMAGE 1
#define CSHIFT_BONUS 2
#define CSHIFT_POWERUP 3
#define NUM_CSHIFTS 4
#define NAME_LENGTH 64
//
// client_state_t should hold all pieces of the client state
//
#define SIGNONS 4 // signon messages to receive before connected
#define MAX_DLIGHTS 32
typedef struct
{
vec3_t origin;
float radius;
float die; // stop lighting after this time
float decay; // drop this each second
float minlight; // don't add when contributing less
int key;
qboolean dark; // subtracts light instead of adding
vec3_t color; //LordHavoc Lit. Support
int type; // color
} dlight_t;
#define MAX_BEAMS 24
typedef struct
{
int entity;
struct model_s *model;
float endtime;
vec3_t start, end;
} beam_t;
#define MAX_EFRAGS 640
#define MAX_MAPSTRING 2048
#define MAX_DEMOS 8
#define MAX_DEMONAME 16
typedef enum {
ca_dedicated, // a dedicated server with no ability to start a client
ca_disconnected, // full screen console with no connection
ca_connected // valid netcon, talking to a server
} cactive_t;
//
// the client_static_t structure is persistant through an arbitrary number
// of server connections
//
typedef struct
{
cactive_t state;
// personalization data sent to server
char mapstring[MAX_QPATH];
char spawnparms[MAX_MAPSTRING]; // to restart a level
// demo loop control
int demonum; // -1 = don't play demos
char demos[MAX_DEMOS][MAX_DEMONAME]; // when not playing
// demo recording info must be here, because record is started before
// entering a map (and clearing client_state_t)
qboolean demorecording;
qboolean demoplayback;
qboolean timedemo;
int forcetrack; // -1 = use normal cd track
FILE *demofile;
int td_lastframe; // to meter out one message a frame
int td_startframe; // host_framecount at start
float td_starttime; // realtime at second frame of timedemo
// connection information
int signon; // 0 to SIGNONS
struct qsocket_s *netcon;
sizebuf_t message; // writing buffer to send to server
} client_static_t;
extern client_static_t cls;
//
// the client_state_t structure is wiped completely at every
// server signon
//
typedef struct
{
int movemessages; // since connecting to this server
// throw out the first couple, so the player
// doesn't accidentally do something the
// first frame
usercmd_t cmd; // last command sent to the server
// information for local display
int stats[MAX_CL_STATS]; // health, etc
int perks; // Perk icons.
int progress_bar; // Perk icons.
float item_gettime[32]; // cl.time of aquiring item, for blinking
float faceanimtime; // use anim frame if cl.time < this
cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups
cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types
// the client maintains its own idea of view angles, which are
// sent to the server each frame. The server sets punchangle when
// the view is temporarliy offset, and an angle reset commands at the start
// of each level and after teleporting.
vec3_t mviewangles[2]; // during demo playback viewangles is lerped
// between these
vec3_t viewangles;
vec3_t mvelocity[2]; // update by server, used for lean+bob
// (0 is newest)
vec3_t velocity; // lerped between mvelocity[0] and [1]
vec3_t punchangle; // temporary offset
vec3_t gun_kick; // temporary kick
// pitch drifting vars
float idealpitch;
float pitchvel;
qboolean nodrift;
float driftmove;
double laststop;
float viewheight;
float crouch; // local amount for smoothing stepups
qboolean paused; // send over by server
qboolean onground;
qboolean inwater;
int intermission; // don't change view angle, full screen, etc
int completed_time; // latched at intermission start
double mtime[2]; // the timestamp of last two messages
double time; // clients view of time, should be between
// servertime and oldservertime to generate
// a lerp point for other data
double oldtime; // previous cl.time, time-oldtime is used
// to decay light values and smooth step ups
double ctime; // joe: copy of cl.time, to avoid incidents caused by rewind
float last_received_message; // (realtime) for net trouble icon
double laser_point_time;
//
// information that is static for the entire time connected to a server
//
struct model_s *model_precache[MAX_MODELS];
struct sfx_s *sound_precache[MAX_SOUNDS];
char levelname[40]; // for display on solo scoreboard
int viewentity; // cl_entitites[cl.viewentity] = player
int maxclients;
int gametype;
// refresh related state
struct model_s *worldmodel; // cl_entitites[0].model
struct efrag_s *free_efrags;
int num_entities; // held in cl_entities array
int num_statics; // held in cl_staticentities array
entity_t viewent; // the gun model
entity_t viewent2; // the second gun model
int cdtrack, looptrack; // cd audio
// frag scoreboard
scoreboard_t *scores; // [cl.maxclients]
#ifdef QUAKE2
// light level at player's position including dlights
// this is sent back to the server each frame
// architectually ugly but it works
int light_level;
#endif
} client_state_t;
//
// cvars
//
extern cvar_t cl_name;
extern cvar_t cl_color;
extern cvar_t cl_upspeed;
extern float cl_forwardspeed;
extern float cl_backspeed;
extern float cl_sidespeed;
extern cvar_t cl_movespeedkey;
extern cvar_t cl_yawspeed;
extern cvar_t cl_pitchspeed;
extern cvar_t cl_anglespeedkey;
extern cvar_t cl_autofire;
extern cvar_t cl_shownet;
extern cvar_t cl_nolerp;
extern cvar_t cl_pitchdriftspeed;
extern cvar_t lookspring;
extern cvar_t lookstrafe;
extern cvar_t sensitivity;
extern cvar_t in_tolerance;
extern cvar_t in_acceleration;
extern cvar_t in_aimassist;
extern cvar_t in_analog_strafe;
extern cvar_t m_pitch;
extern cvar_t m_yaw;
extern cvar_t m_forward;
extern cvar_t m_side;
extern cvar_t in_mlook;
#define MAX_TEMP_ENTITIES 64 // lightning bolts, etc
#define MAX_STATIC_ENTITIES 128 // torches, etc
extern client_state_t cl;
// FIXME, allocate dynamically
extern efrag_t cl_efrags[MAX_EFRAGS];
extern entity_t cl_entities[MAX_EDICTS];
extern entity_t cl_static_entities[MAX_STATIC_ENTITIES];
extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
extern dlight_t cl_dlights[MAX_DLIGHTS];
extern entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
extern beam_t cl_beams[MAX_BEAMS];
//=============================================================================
//
// cl_main
//
dlight_t *CL_AllocDlight (int key);
void CL_DecayLights (void);
void CL_Init (void);
void CL_EstablishConnection (char *host);
void CL_Signon1 (void);
void CL_Signon2 (void);
void CL_Signon3 (void);
void CL_Signon4 (void);
void CL_Disconnect (void);
void CL_Disconnect_f (void);
void CL_NextDemo (void);
#define MAX_VISEDICTS 256
extern int cl_numvisedicts;
extern entity_t *cl_visedicts[MAX_VISEDICTS];
extern int cl_numstaticbrushmodels;
extern entity_t *cl_staticbrushmodels[MAX_VISEDICTS];
// model indexes
typedef enum modelindex_s
{
mi_player,
mi_eyes,
mi_flame0,
mi_flame1,
mi_flame2,
mi_q3torso,
mi_q3head,
/*
mi_vw_light,
mi_vw_nail1,
mi_vw_nail2,
mi_vw_rock1,
mi_vw_rock2,
mi_vw_shot1,
mi_vw_shot2,
mi_vw_player,
*/
NUM_MODELINDEX
} modelindex_t;
extern modelindex_t cl_modelindex[NUM_MODELINDEX];
extern char *cl_modelnames[NUM_MODELINDEX];
//
// cl_input
//
typedef struct
{
int down[2]; // key nums holding it down
int state; // low bit is down state
} kbutton_t;
extern kbutton_t in_klook;
extern kbutton_t in_strafe;
extern kbutton_t in_speed;
void CL_InitInput (void);
void CL_SendCmd (void);
void CL_SendMove (usercmd_t *cmd);
void CL_ParseTEnt (void);
void CL_UpdateTEnts (void);
void CL_ClearState (void);
int CL_ReadFromServer (void);
void CL_WriteToServer (usercmd_t *cmd);
void CL_BaseMove (usercmd_t *cmd);
float CL_KeyState (kbutton_t *key);
char *Key_KeynumToString (int keynum);
//
// cl_demo.c
//
void CL_StopPlayback (void);
int CL_GetMessage (void);
void CL_Stop_f (void);
void CL_Record_f (void);
void CL_PlayDemo_f (void);
void CL_TimeDemo_f (void);
//
// cl_parse.c
//
void CL_ParseServerMessage (void);
void CL_NewTranslation (int slot);
//
// view
//
void V_StartPitchDrift (void);
void V_StopPitchDrift (void);
void V_RenderView (void);
void V_UpdatePalette (void);
void V_Register (void);
void V_ParseDamage (void);
void V_SetContentsColor (int contents);
//
// cl_tent
//
void CL_InitTEnts (void);
void CL_SignonReply (void);
qboolean TraceLineN (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal);

1744
source/ctr/common.c Normal file

File diff suppressed because it is too large Load diff

195
source/ctr/common.h Normal file
View file

@ -0,0 +1,195 @@
/*
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.
*/
// comndef.h -- general definitions
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#define bound(a, b, c) ((a) >= (c) ? (a) : (b) < (a) ? (a) : (b) > (c) ? (c) : (b))
#if !defined BYTE_DEFINED
typedef unsigned char byte;
#define BYTE_DEFINED 1
#endif
#undef true
#undef false
typedef enum {false, true} qboolean;
//============================================================================
typedef struct sizebuf_s
{
qboolean allowoverflow; // if false, do a Sys_Error
qboolean overflowed; // set to true if the buffer size failed
byte *data;
int maxsize;
int cursize;
} sizebuf_t;
void SZ_Alloc (sizebuf_t *buf, int startsize);
void SZ_Free (sizebuf_t *buf);
void SZ_Clear (sizebuf_t *buf);
void *SZ_GetSpace (sizebuf_t *buf, int length);
void SZ_Write (sizebuf_t *buf, void *data, int length);
void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf
//============================================================================
typedef struct link_s
{
struct link_s *prev, *next;
} link_t;
void ClearLink (link_t *l);
void RemoveLink (link_t *l);
void InsertLinkBefore (link_t *l, link_t *before);
void InsertLinkAfter (link_t *l, link_t *after);
// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
// ent = STRUCT_FROM_LINK(link,entity_t,order)
// FIXME: remove this mess!
#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m)))
//============================================================================
#ifndef NULL
#define NULL ((void *)0)
#endif
#define Q_MAXCHAR ((char)0x7f)
#define Q_MAXSHORT ((short)0x7fff)
#define Q_MAXINT ((int)0x7fffffff)
#define Q_MAXLONG ((int)0x7fffffff)
#define Q_MAXFLOAT ((int)0x7fffffff)
#define Q_MINCHAR ((char)0x80)
#define Q_MINSHORT ((short)0x8000)
#define Q_MININT ((int)0x80000000)
#define Q_MINLONG ((int)0x80000000)
#define Q_MINFLOAT ((int)0x7fffffff)
//============================================================================
extern qboolean bigendien;
extern short (*BigShort) (short l);
extern short (*LittleShort) (short l);
extern int (*BigLong) (int l);
#define LittleLong(l) l
#define LittleShort(l) l
#define LittleFloat(l) l
//============================================================================
void MSG_WriteChar (sizebuf_t *sb, int c);
void MSG_WriteByte (sizebuf_t *sb, int c);
void MSG_WriteShort (sizebuf_t *sb, int c);
void MSG_WriteLong (sizebuf_t *sb, int c);
void MSG_WriteFloat (sizebuf_t *sb, float f);
void MSG_WriteString (sizebuf_t *sb, char *s);
void MSG_WriteCoord (sizebuf_t *sb, float f);
void MSG_WriteAngle (sizebuf_t *sb, float f);
extern int msg_readcount;
extern qboolean msg_badread; // set if a read goes beyond end of message
void MSG_BeginReading (void);
int MSG_ReadChar (void);
int MSG_ReadByte (void);
int MSG_ReadShort (void);
int MSG_ReadLong (void);
float MSG_ReadFloat (void);
char *MSG_ReadString (void);
float MSG_ReadCoord (void);
float MSG_ReadAngle (void);
//============================================================================
void Q_memset (void *dest, int fill, int count);
void Q_memcpy (void *dest, void *src, int count);
int Q_memcmp (void *m1, void *m2, int count);
void Q_strcpy (char *dest, char *src);
void Q_strncpy (char *dest, char *src, int count);
int Q_strlen (char *str);
char *Q_strrchr (char *s, char c);
void Q_strcat (char *dest, char *src);
int Q_strcasecmp (char *s1, char *s2);
int Q_strncasecmp (char *s1, char *s2, int n);
int Q_atoi (char *str);
float Q_atof (char *str);
int q_snprintf (char *str, size_t size, const char *format, ...);
int q_vsnprintf(char *str, size_t size, const char *format, va_list args);
//============================================================================
extern char com_token[1024];
extern qboolean com_eof;
char *COM_Parse (char *data);
extern int com_argc;
extern char **com_argv;
int COM_CheckParm (char *parm);
void COM_Init (char *path);
void COM_InitArgv (int argc, char **argv);
char *COM_SkipPath (char *pathname);
void COM_StripExtension (char *in, char *out);
void COM_FileBase (char *in, char *out);
void COM_DefaultExtension (char *path, char *extension);
char *va(char *format, ...);
// does a varargs printf into a temp buffer
//============================================================================
extern int com_filesize;
struct cache_user_s;
extern char com_gamedir[MAX_OSPATH];
void COM_WriteFile (char *filename, void *data, int len);
int COM_OpenFile (char *filename, int *hndl);
int COM_FOpenFile (char *filename, FILE **file);
void COM_CloseFile (int h);
byte *COM_LoadStackFile (char *path, void *buffer, int bufsize);
byte *COM_LoadTempFile (char *path);
byte *COM_LoadHunkFile (char *path);
void COM_LoadCacheFile (char *path, struct cache_user_s *cu);
extern struct cvar_s registered;
extern qboolean standard_quake, rogue, hipnotic;
void Q_strncpyz (char *dest, char *src, size_t size); //Diabolickal HLBSP

100
source/ctr/dosisms.h Normal file
View file

@ -0,0 +1,100 @@
/*
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.
*/
//
// dosisms.h: I'd call it dos.h, but the name's taken
//
#ifndef _DOSISMS_H_
#define _DOSISMS_H_
int dos_lockmem(void *addr, int size);
int dos_unlockmem(void *addr, int size);
typedef union {
struct {
unsigned long edi;
unsigned long esi;
unsigned long ebp;
unsigned long res;
unsigned long ebx;
unsigned long edx;
unsigned long ecx;
unsigned long eax;
} d;
struct {
unsigned short di, di_hi;
unsigned short si, si_hi;
unsigned short bp, bp_hi;
unsigned short res, res_hi;
unsigned short bx, bx_hi;
unsigned short dx, dx_hi;
unsigned short cx, cx_hi;
unsigned short ax, ax_hi;
unsigned short flags;
unsigned short es;
unsigned short ds;
unsigned short fs;
unsigned short gs;
unsigned short ip;
unsigned short cs;
unsigned short sp;
unsigned short ss;
} x;
struct {
unsigned char edi[4];
unsigned char esi[4];
unsigned char ebp[4];
unsigned char res[4];
unsigned char bl, bh, ebx_b2, ebx_b3;
unsigned char dl, dh, edx_b2, edx_b3;
unsigned char cl, ch, ecx_b2, ecx_b3;
unsigned char al, ah, eax_b2, eax_b3;
} h;
} regs_t;
unsigned int ptr2real(void *ptr);
void *real2ptr(unsigned int real);
void *far2ptr(unsigned int farptr);
unsigned int ptr2far(void *ptr);
int dos_inportb(int port);
int dos_inportw(int port);
void dos_outportb(int port, int val);
void dos_outportw(int port, int val);
void dos_irqenable(void);
void dos_irqdisable(void);
void dos_registerintr(int intr, void (*handler)(void));
void dos_restoreintr(int intr);
int dos_int86(int vec);
void *dos_getmemory(int size);
void dos_freememory(void *ptr);
void dos_usleep(int usecs);
int dos_getheapsize(void);
extern regs_t regs;
#endif // _DOSISMS_H_

156
source/ctr/gl/gl_decal.c Normal file
View file

@ -0,0 +1,156 @@
#include "../../quakedef.h"
void R_SpawnDecal (vec3_t center, vec3_t normal, vec3_t tangent, int tex, int size, int isbsp)
{
// naievil -- fixme
/*
int a;
float width, height, depth, d, one_over_w, one_over_h;
vec3_t binormal, test = {0.5, 0.5, 0.5};
decal_t *dec;
if (!qmb_initialized)
return;
// allocate decal
if (!free_decals)
return;
dec = free_decals;
free_decals = dec->next;
dec->next = active_decals;
active_decals = dec;
VectorNormalize (test);
CrossProduct (normal, test, tangent);
VectorCopy (center, dec->origin);
VectorCopy (tangent, dec->tangent);
VectorCopy (normal, dec->normal);
VectorNormalize (tangent);
VectorNormalize (normal);
CrossProduct (normal, tangent, binormal);
VectorNormalize (binormal);
width = RandomMinMax (size * 0.5, size);
height = width;
depth = width * 0.5;
dec->radius = fmax(fmax(width, height), depth);
dec->starttime = cl.time;
dec->bspdecal = isbsp;
dec->die = (isbsp ? 0 : cl.time + r_decaltime.value);
dec->texture = tex;
// Calculate boundary planes
d = DotProduct (center, tangent);
VectorCopy (tangent, leftPlane.normal);
leftPlane.dist = -(width * 0.5 - d);
VectorNegate (tangent, tangent);
VectorCopy (tangent, rightPlane.normal);
VectorNegate (tangent, tangent);
rightPlane.dist = -(width * 0.5 + d);
d = DotProduct (center, binormal);
VectorCopy (binormal, bottomPlane.normal);
bottomPlane.dist = -(height * 0.5 - d);
VectorNegate (binormal, binormal);
VectorCopy (binormal, topPlane.normal);
VectorNegate (binormal, binormal);
topPlane.dist = -(height * 0.5 + d);
d = DotProduct (center, normal);
VectorCopy (normal, backPlane.normal);
backPlane.dist = -(depth - d);
VectorNegate (normal, normal);
VectorCopy (normal, frontPlane.normal);
VectorNegate (normal, normal);
frontPlane.dist = -(depth + d);
// Begin with empty mesh
dec->vertexCount = 0;
dec->triangleCount = 0;
// Clip decal to bsp
DecalWalkBsp_R (dec, cl.worldmodel->nodes);
// This happens when a decal is to far from any surface or the surface is to steeply sloped
if (dec->triangleCount == 0)
{ // deallocate decal
active_decals = dec->next;
dec->next = free_decals;
free_decals = dec;
return;
}
// Assign texture mapping coordinates
one_over_w = 1.0F / width;
one_over_h = 1.0F / height;
for (a = 0 ; a < dec->vertexCount ; a++)
{
float s, t;
vec3_t v;
VectorSubtract (dec->vertexArray[a], center, v);
s = DotProduct (v, tangent) * one_over_w + 0.5F;
t = DotProduct (v, binormal) * one_over_h + 0.5F;
dec->texcoordArray[a][0] = s;
dec->texcoordArray[a][1] = t;
}
*/
}
//Revamped by blubs
void R_SpawnDecalStatic (vec3_t org, int tex, int size)
{
/*
int i;
float frac, bestfrac;
vec3_t tangent, v, bestorg, normal, bestnormal, org2;
vec3_t tempVec;
if (!qmb_initialized)
return;
VectorClear (bestorg);
VectorClear (bestnormal);
VectorClear(tempVec);
bestfrac = 10;
for (i = 0 ; i < 26 ; i++)
{
//Reference: i = 0: check straight up, i = 1: check straight down
//1 < i < 10: Check sideways in increments of 45 degrees
//9 < i < 18: Check angled 45 degrees down in increments of 45 degrees
//17 < i : Check angled 45 degrees up in increments of 45 degrees
org2[0] = (((((i - 2) % 8) < 2) || (((i - 2) % 8) == 7)) ? 1 : 0 ) + ((((i - 2) % 8) > 2 && ((i - 2) % 8) < 6) ? -1 : 0 );
org2[1] = ((((i - 2) % 8) > 0 && ((i - 2) % 8) < 4) ? 1 : 0 ) + ((((i - 2) % 8) > 4 && ((i - 2) % 8) < 7) ? -1 : 0 );
org2[2] = ((i == 0) ? 1 : 0) + ((i == 1) ? -1 : 0) + (((i > 9) && (i < 18)) ? 1 : 0) + ((i > 17) ? -1 : 0);
VectorCopy(org,tempVec);
VectorMA(tempVec, -0.1,org2,tempVec);
VectorMA (org, 20, org2, org2);
TraceLineN (tempVec, org2, v, normal);
VectorSubtract(org2,tempVec,org2);//goal
VectorSubtract(v,tempVec,tempVec);//collision
if(VectorLength(org2) == 0)
return;
frac = VectorLength(tempVec) / VectorLength(org2);
if(frac < 1 && frac < bestfrac)
{
bestfrac = frac;
VectorCopy(v,bestorg);
VectorCopy(normal, bestnormal);
CrossProduct(normal,bestnormal,tangent);
}
}
if (bestfrac < 1)
R_SpawnDecal (bestorg, bestnormal, tangent, tex, size, 0);
*/
}

2
source/ctr/gl/gl_decal.h Normal file
View file

@ -0,0 +1,2 @@
void R_SpawnDecal (vec3_t center, vec3_t normal, vec3_t tangent, int tex, int size, int isbsp);
void R_SpawnDecalStatic (vec3_t org, int tex, int size);

2338
source/ctr/gl/gl_draw.c Normal file

File diff suppressed because it is too large Load diff

517
source/ctr/gl/gl_fog.c Normal file
View file

@ -0,0 +1,517 @@
/*
Fogging system based on FitzQuake's implementation
Now with Quakespasm bits thrown into it!
*/
#include "../../quakedef.h"
//==============================================================================
//
// GLOBAL FOG
//
//==============================================================================
#define DEFAULT_DENSITY 1.0
#define DEFAULT_GRAY 0.3
float density = 1.0;
float fog_density_gl;
float fog_start;
float fog_end;
float fog_red;
float fog_green;
float fog_blue;
float old_density;
float old_start;
float old_end;
float old_red;
float old_green;
float old_blue;
float fade_time; //duration of fade
float fade_done; //time when fade will be done
/*
=============
Fog_Update
update internal variables
=============
*/
void Fog_Update (float start, float end, float red, float green, float blue, float time)
{
//save previous settings for fade
if (time > 0)
{
//check for a fade in progress
if (fade_done > cl.time)
{
float f;
f = (fade_done - cl.time) / fade_time;
old_start = f * old_start + (1.0 - f) * fog_start;
old_end = f * old_end + (1.0 - f) * fog_end;
old_red = f * old_red + (1.0 - f) * fog_red;
old_green = f * old_green + (1.0 - f) * fog_green;
old_blue = f * old_blue + (1.0 - f) * fog_blue;
old_density = f * old_density + (1.0 - f) * fog_density_gl;
}
else
{
old_start = fog_start;
old_end = fog_end;
old_red = fog_red;
old_green = fog_green;
old_blue = fog_blue;
old_density = fog_density_gl;
}
}
fog_start = start;
fog_end = end;
fog_red = red;
fog_green = green;
fog_blue = blue;
fade_time = time;
fade_done = cl.time + time;
fog_density_gl = ((fog_start / fog_end))/3.5;
}
/*
=============
Fog_ParseServerMessage
handle an SVC_FOG message from server
=============
*/
void Fog_ParseServerMessage (void)
{
float start, end, red, green, blue, time;
start = MSG_ReadByte() / 255.0;
end = MSG_ReadByte() / 255.0;
red = MSG_ReadByte() / 255.0;
green = MSG_ReadByte() / 255.0;
blue = MSG_ReadByte() / 255.0;
time = MSG_ReadShort() / 100.0;
Fog_Update (start, end, red, green, blue, time);
}
/*
=============
Fog_FogCommand_f
handle the 'fog' console command
=============
*/
void Fog_FogCommand_f (void)
{
switch (Cmd_Argc())
{
default:
case 1:
Con_Printf("usage:\n");
Con_Printf(" fog <fade>\n");
Con_Printf(" fog <start> <end>\n");
Con_Printf(" fog <red> <green> <blue>\n");
Con_Printf(" fog <fade> <red> <green> <blue>\n");
Con_Printf(" fog <start> <end> <red> <green> <blue>\n");
Con_Printf(" fog <start> <end> <red> <green> <blue> <fade>\n");
Con_Printf("current values:\n");
Con_Printf(" \"start\" is \"%f\"\n", fog_start);
Con_Printf(" \"end\" is \"%f\"\n", fog_end);
Con_Printf(" \"red\" is \"%f\"\n", fog_red);
Con_Printf(" \"green\" is \"%f\"\n", fog_green);
Con_Printf(" \"blue\" is \"%f\"\n", fog_blue);
Con_Printf(" \"fade\" is \"%f\"\n", fade_time);
break;
case 2: //TEST
Fog_Update(fog_start,
fog_end,
fog_red,
fog_green,
fog_blue,
atof(Cmd_Argv(1)));
break;
case 3:
Fog_Update(atof(Cmd_Argv(1)),
atof(Cmd_Argv(2)),
fog_red,
fog_green,
fog_blue,
0.0);
break;
case 4:
Fog_Update(fog_start,
fog_end,
CLAMP(0.0, atof(Cmd_Argv(1)), 100.0),
CLAMP(0.0, atof(Cmd_Argv(2)), 100.0),
CLAMP(0.0, atof(Cmd_Argv(3)), 100.0),
0.0);
break;
case 5: //TEST
Fog_Update(fog_start,
fog_end,
CLAMP(0.0, atof(Cmd_Argv(1)), 100.0),
CLAMP(0.0, atof(Cmd_Argv(2)), 100.0),
CLAMP(0.0, atof(Cmd_Argv(3)), 100.0),
atof(Cmd_Argv(4)));
break;
case 6:
Fog_Update(atof(Cmd_Argv(1)),
atof(Cmd_Argv(2)),
CLAMP(0.0, atof(Cmd_Argv(3)), 100.0),
CLAMP(0.0, atof(Cmd_Argv(4)), 100.0),
CLAMP(0.0, atof(Cmd_Argv(5)), 100.0),
0.0);
break;
case 7:
Fog_Update(atof(Cmd_Argv(1)),
atof(Cmd_Argv(2)),
CLAMP(0.0, atof(Cmd_Argv(3)), 100.0),
CLAMP(0.0, atof(Cmd_Argv(4)), 100.0),
CLAMP(0.0, atof(Cmd_Argv(5)), 100.0),
atof(Cmd_Argv(6)));
break;
}
}
/*
=============
Fog_ParseWorldspawn
called at map load
=============
*/
void Fog_ParseWorldspawn (void)
{
char key[128], value[4096];
const char *data;
fog_density_gl = DEFAULT_DENSITY;
//initially no fog
fog_start = 0;
old_start = 0;
fog_end = 4000;
old_end = 4000;
fog_red = 0.0;
old_red = 0.0;
fog_green = 0.0;
old_green = 0.0;
fog_blue = 0.0;
old_blue = 0.0;
fade_time = 0.0;
fade_done = 0.0;
data = COM_Parse(cl.worldmodel->entities);
if (!data)
return; // error
if (com_token[0] != '{')
return; // error
while (1)
{
data = COM_Parse(data);
if (!data)
return; // error
if (com_token[0] == '}')
break; // end of worldspawn
if (com_token[0] == '_')
strcpy(key, com_token + 1);
else
strcpy(key, com_token);
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
data = COM_Parse(data);
if (!data)
return; // error
strcpy(value, com_token);
if (!strcmp("fog", key))
{
sscanf(value, "%f %f %f %f %f", &fog_start, &fog_end, &fog_red, &fog_green, &fog_blue);
}
fog_density_gl = ((fog_start / fog_end))/3.5;
}
}
/*
=============
Fog_GetColor
calculates fog color for this frame, taking into account fade times
=============
*/
float *Fog_GetColor (void)
{
static float c[4]; // = {0.1f, 0.1f, 0.1f, 1.0f}
float f;
int i;
if (fade_done > cl.time)
{
f = (fade_done - cl.time) / fade_time;
c[0] = f * old_red + (1.0 - f) * fog_red;
c[1] = f * old_green + (1.0 - f) * fog_green;
c[2] = f * old_blue + (1.0 - f) * fog_blue;
c[3] = 1.0;
}
else
{
c[0] = fog_red;
c[1] = fog_green;
c[2] = fog_blue;
c[3] = 1.0;
}
//find closest 24-bit RGB value, so solid-colored sky can match the fog perfectly
for (i=0;i<3;i++)
c[i] = (float)(rint(c[i] * 255)) / 255.0f;
for (i = 0; i < 3; i++)
c[i] /= 64.0;
return c;
}
/*
=============
Fog_GetDensity
returns current density of fog
=============
*/
float Fog_GetDensity (void)
{
float f;
if (fade_done > cl.time)
{
f = (fade_done - cl.time) / fade_time;
return f * old_density + (1.0 - f) * fog_density_gl;
}
else
return fog_density_gl;
}
/*
=============
Fog_SetupFrame
called at the beginning of each frame
=============
*/
void Fog_SetupFrame (void)
{
glFogfv(GL_FOG_COLOR, Fog_GetColor());
glFogf(GL_FOG_DENSITY, 0.2f);
glFogf(GL_FOG_START, fog_start);
glFogf(GL_FOG_END, fog_end);
}
/*
=============
Fog_SetColorForSkyS
Start called before drawing flat-colored sky
Crow_bar*
=============
*/
void Fog_SetColorForSkyS (void)
{
if (fog_end > 0.0f && r_skyfog.value)
{
float a = fog_end * 0.00025f;
float r = fog_red * 0.01f + (a * 0.25f);
float g = fog_green * 0.01f + (a * 0.25f);
float b = fog_blue * 0.01f + (a * 0.25f);
if (a > 1.0f)
a = 1.0f;
if (r > 1.0f)
r = 1.0f;
if (g > 1.0f)
g = 1.0f;
if (b > 1.0f)
b = 1.0f;
glColor4f(r, g, b, a);
}
}
/*
=============
Fog_GetStart
returns current start of fog
=============
*/
float Fog_GetStart (void)
{
float f;
if (fade_done > cl.time)
{
f = (fade_done - cl.time) / fade_time;
return f * old_start + (1.0 - f) * fog_start;
}
else
return fog_start;
}
/*
=============
Fog_GetEnd
returns current end of fog
=============
*/
float Fog_GetEnd (void)
{
float f;
if (fade_done > cl.time)
{
f = (fade_done - cl.time) / fade_time;
return f * old_start + (1.0 - f) * fog_end;
}
else
return fog_end;
}
/*
=============
Fog_SetColorForSky
End called before drawing flat-colored sky
Crow_bar*
=============
*/
void Fog_SetColorForSkyE (void)
{
if (fog_end > 0.0f && r_skyfog.value)
{
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
}
/*
=============
Fog_EnableGFog
called before drawing stuff that should be fogged
=============
*/
void Fog_EnableGFog (void)
{
if (!Fog_GetStart() == 0 || !Fog_GetEnd() <= 0) {
glEnable(GL_FOG);
}
}
/*
=============
Fog_DisableGFog
called after drawing stuff that should be fogged
=============
*/
void Fog_DisableGFog (void)
{
if (!Fog_GetStart() == 0 || !Fog_GetEnd() <= 0)
glDisable(GL_FOG);
}
/*
=============
Fog_SetColorForSky
called before drawing flat-colored sky
=============
*/
/*
void Fog_SetColorForSky (void)
{
float c[3];
float f, d;
if (fade_done > cl.time)
{
f = (fade_done - cl.time) / fade_time;
d = f * old_density + (1.0 - f) * fog_density;
c[0] = f * old_red + (1.0 - f) * fog_red;
c[1] = f * old_green + (1.0 - f) * fog_green;
c[2] = f * old_blue + (1.0 - f) * fog_blue;
}
else
{
d = fog_density;
c[0] = fog_red;
c[1] = fog_green;
c[2] = fog_blue;
}
if (d > 0)
glColor3fv (c);
}
*/
//==============================================================================
//
// VOLUMETRIC FOG
//
//==============================================================================
/*
void Fog_DrawVFog (void){}
void Fog_MarkModels (void){}
*/
//==============================================================================
//
// INIT
//
//==============================================================================
/*
=============
Fog_NewMap
called whenever a map is loaded
=============
*/
void Fog_NewMap (void)
{
Fog_ParseWorldspawn (); //for global fog
}
/*
=============
Fog_Init
called when quake initializes
=============
*/
void Fog_Init (void)
{
Cmd_AddCommand ("fog",Fog_FogCommand_f);
//set up global fog
fog_start = 300;
fog_end = 4000;
fog_red = 0.5;
fog_green = 0.5;
fog_blue = 0.5;
fade_time = 1;
fog_density_gl = DEFAULT_DENSITY;
fade_time = 1;
glFogi(GL_FOG_MODE, GL_LINEAR);
}

318
source/ctr/gl/gl_mesh.c Normal file
View file

@ -0,0 +1,318 @@
/*
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.
*/
// gl_mesh.c: triangle model functions
#include "../../quakedef.h"
/*
=================================================================
ALIAS MODEL DISPLAY LIST GENERATION
=================================================================
*/
model_t *aliasmodel;
aliashdr_t *paliashdr;
qboolean used[8192];
// the command list holds counts and s/t values that are valid for
// every frame
int commands[8192];
int numcommands;
// all frames will have their vertexes rearranged and expanded
// so they are in the order expected by the command list
int vertexorder[8192];
int numorder;
int allverts, alltris;
int stripverts[128];
int striptris[128];
int stripcount;
/*
================
StripLength
================
*/
int StripLength (int starttri, int startv)
{
int m1, m2;
int j;
mtriangle_t *last, *check;
int k;
used[starttri] = 2;
last = &triangles[starttri];
stripverts[0] = last->vertindex[(startv)%3];
stripverts[1] = last->vertindex[(startv+1)%3];
stripverts[2] = last->vertindex[(startv+2)%3];
striptris[0] = starttri;
stripcount = 1;
m1 = last->vertindex[(startv+2)%3];
m2 = last->vertindex[(startv+1)%3];
// look for a matching triangle
nexttri:
for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)
{
if (check->facesfront != last->facesfront)
continue;
for (k=0 ; k<3 ; k++)
{
if (check->vertindex[k] != m1)
continue;
if (check->vertindex[ (k+1)%3 ] != m2)
continue;
// this is the next part of the fan
// if we can't use this triangle, this tristrip is done
if (used[j])
goto done;
// the new edge
if (stripcount & 1)
m2 = check->vertindex[ (k+2)%3 ];
else
m1 = check->vertindex[ (k+2)%3 ];
stripverts[stripcount+2] = check->vertindex[ (k+2)%3 ];
striptris[stripcount] = j;
stripcount++;
used[j] = 2;
goto nexttri;
}
}
done:
// clear the temp used flags
for (j=starttri+1 ; j<pheader->numtris ; j++)
if (used[j] == 2)
used[j] = 0;
return stripcount;
}
/*
===========
FanLength
===========
*/
int FanLength (int starttri, int startv)
{
int m1, m2;
int j;
mtriangle_t *last, *check;
int k;
used[starttri] = 2;
last = &triangles[starttri];
stripverts[0] = last->vertindex[(startv)%3];
stripverts[1] = last->vertindex[(startv+1)%3];
stripverts[2] = last->vertindex[(startv+2)%3];
striptris[0] = starttri;
stripcount = 1;
m1 = last->vertindex[(startv+0)%3];
m2 = last->vertindex[(startv+2)%3];
// look for a matching triangle
nexttri:
for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)
{
if (check->facesfront != last->facesfront)
continue;
for (k=0 ; k<3 ; k++)
{
if (check->vertindex[k] != m1)
continue;
if (check->vertindex[ (k+1)%3 ] != m2)
continue;
// this is the next part of the fan
// if we can't use this triangle, this tristrip is done
if (used[j])
goto done;
// the new edge
m2 = check->vertindex[ (k+2)%3 ];
stripverts[stripcount+2] = m2;
striptris[stripcount] = j;
stripcount++;
used[j] = 2;
goto nexttri;
}
}
done:
// clear the temp used flags
for (j=starttri+1 ; j<pheader->numtris ; j++)
if (used[j] == 2)
used[j] = 0;
return stripcount;
}
/*
================
BuildTris
Generate a list of trifans or strips
for the model, which holds for all frames
================
*/
void BuildTris (void)
{
int i, j, k;
int startv;
mtriangle_t *last, *check;
int m1, m2;
int striplength;
trivertx_t *v;
mtriangle_t *tv;
float s, t;
int index;
int len, bestlen, besttype;
int bestverts[1024];
int besttris[1024];
int type;
//
// build tristrips
//
numorder = 0;
numcommands = 0;
memset (used, 0, sizeof(used));
for (i=0 ; i<pheader->numtris ; i++)
{
// pick an unused triangle and start the trifan
if (used[i])
continue;
bestlen = 0;
for (type = 0 ; type < 2 ; type++)
// type = 1;
{
for (startv =0 ; startv < 3 ; startv++)
{
if (type == 1)
len = StripLength (i, startv);
else
len = FanLength (i, startv);
if (len > bestlen)
{
besttype = type;
bestlen = len;
for (j=0 ; j<bestlen+2 ; j++)
bestverts[j] = stripverts[j];
for (j=0 ; j<bestlen ; j++)
besttris[j] = striptris[j];
}
}
}
// mark the tris on the best strip as used
for (j=0 ; j<bestlen ; j++)
used[besttris[j]] = 1;
if (besttype == 1)
commands[numcommands++] = (bestlen+2);
else
commands[numcommands++] = -(bestlen+2);
for (j=0 ; j<bestlen+2 ; j++)
{
// emit a vertex into the reorder buffer
k = bestverts[j];
vertexorder[numorder++] = k;
// emit s/t coords into the commands stream
s = stverts[k].s;
t = stverts[k].t;
if (!triangles[besttris[0]].facesfront && stverts[k].onseam)
s += pheader->skinwidth / 2; // on back side
s = (s + 0.5) / pheader->skinwidth;
t = (t + 0.5) / pheader->skinheight;
*(float *)&commands[numcommands++] = s;
*(float *)&commands[numcommands++] = t;
}
}
commands[numcommands++] = 0; // end of list marker
Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands);
allverts += numorder;
alltris += pheader->numtris;
}
/*
================
GL_MakeAliasModelDisplayLists
================
*/
void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr)
{
int i, j;
maliasgroup_t *paliasgroup;
int *cmds;
trivertx_t *verts;
char cache[MAX_QPATH], fullpath[MAX_OSPATH], *c;
FILE *f;
int len;
byte *data;
aliasmodel = m;
paliashdr = hdr; // (aliashdr_t *)Mod_Extradata (m);
BuildTris (); // trifans or lists
paliashdr->poseverts = numorder;
cmds = Hunk_Alloc (numcommands * 4);
paliashdr->commands = (byte *)cmds - (byte *)paliashdr;
memcpy (cmds, commands, numcommands * 4);
verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts
* sizeof(trivertx_t) );
paliashdr->posedata = (byte *)verts - (byte *)paliashdr;
for (i=0 ; i<paliashdr->numposes ; i++)
for (j=0 ; j<numorder ; j++)
*verts++ = poseverts[i][vertexorder[j]];
}

2130
source/ctr/gl/gl_model.c Normal file

File diff suppressed because it is too large Load diff

468
source/ctr/gl/gl_model.h Normal file
View file

@ -0,0 +1,468 @@
/*
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.
*/
#ifndef __MODEL__
#define __MODEL__
#include "../modelgen.h"
#include "../../spritegn.h"
/*
d*_t structures are on-disk representations
m*_t structures are in-memory
*/
// entity effects
#define EF_BLUELIGHT 1
#define EF_MUZZLEFLASH 2
#define EF_BRIGHTLIGHT 4
#define EF_REDLIGHT 8
#define EF_ORANGELIGHT 16
#define EF_GREENLIGHT 32
#define EF_PINKLIGHT 64 // formerly EF_LIGHT
#define EF_NODRAW 128
#define EF_LIMELIGHT 256 // formerly EF_BRIGHTFIELD
#define EF_FULLBRIGHT 512
#define EF_CYANLIGHT 1024 // formerly EF_DARKLIGHT
#define EF_YELLOWLIGHT 2048 // formerly EF_DARKFIELD
#define EF_PURPLELIGHT 4096
#define EF_RAYRED 8196 // red trail for porter x2
#define EF_RAYGREEN 16384 // green trail for ray gun
/*
==============================================================================
BRUSH MODELS
==============================================================================
*/
//
// in memory representation
//
typedef struct
{
vec3_t position;
} mvertex_t;
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
// plane_t structure
typedef struct mplane_s
{
vec3_t normal;
float dist;
byte type; // for texture axis selection and fast side tests
byte signbits; // signx + signy<<1 + signz<<1
byte pad[2];
} mplane_t;
typedef struct texture_s
{
char name[16];
unsigned width, height;
int gl_texturenum;
struct msurface_s *texturechain; // for gl_texsort drawing
int anim_total; // total tenths in sequence ( 0 = no)
int anim_min, anim_max; // time for this frame min <=time< max
struct texture_s *anim_next; // in the animation sequence
struct texture_s *alternate_anims; // bmodels in frmae 1 use these
unsigned offsets[MIPLEVELS]; // four mip maps stored
} texture_t;
#define SURF_PLANEBACK 2
#define SURF_DRAWSKY 4
#define SURF_DRAWSPRITE 8
#define SURF_DRAWTURB 0x10
#define SURF_DRAWTILED 0x20
#define SURF_DRAWBACKGROUND 0x40
#define SURF_UNDERWATER 0x80
#define TEXFLAG_NODRAW 256
#define TEXFLAG_LIGHT 512
typedef struct
{
unsigned short v[2];
unsigned int cachededgeoffset;
} medge_t;
typedef struct
{
float vecs[2][4];
float mipadjust;
texture_t *texture;
int flags;
} mtexinfo_t;
#define VERTEXSIZE 7
typedef struct glpoly_s
{
struct glpoly_s *next;
struct glpoly_s *chain;
int numverts;
int flags; // for SURF_UNDERWATER
float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2)
// vec3_t midpoint;//MHQuake // naievil -- fixme: this guy is causing some kind of rendering issue
} glpoly_t;
typedef struct msurface_s
{
int visframe; // should be drawn when node is crossed
mplane_t *plane;
int flags;
int firstedge; // look up in model->surfedges[], negative numbers
int numedges; // are backwards edges
short texturemins[2];
short extents[2];
int light_s, light_t; // gl lightmap coordinates
glpoly_t *polys; // multiple if warped
struct msurface_s *texturechain;
mtexinfo_t *texinfo;
// lighting info
int dlightframe;
unsigned int dlightbits[(MAX_DLIGHTS + 31) >> 5];
// int is 32 bits, need an array for MAX_DLIGHTS > 32
int lightmaptexturenum;
byte styles[MAXLIGHTMAPS];
int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap
qboolean cached_dlight; // true if dynamic light in cache
byte *samples; // [numstyles*surfsize]
} msurface_t;
typedef struct mnode_s
{
// common with leaf
int contents; // 0, to differentiate from leafs
int visframe; // node needs to be traversed if current
float minmaxs[6]; // for bounding box culling
struct mnode_s *parent;
// node specific
mplane_t *plane;
struct mnode_s *children[2];
unsigned short firstsurface;
unsigned short numsurfaces;
} mnode_t;
typedef struct mleaf_s
{
// common with node
int contents; // wil be a negative contents number
int visframe; // node needs to be traversed if current
float minmaxs[6]; // for bounding box culling
struct mnode_s *parent;
// leaf specific
byte *compressed_vis;
efrag_t *efrags;
msurface_t **firstmarksurface;
int nummarksurfaces;
int key; // BSP sequence number for leaf's contents
byte ambient_sound_level[NUM_AMBIENTS];
} mleaf_t;
typedef struct
{
dclipnode_t *clipnodes;
mplane_t *planes;
int firstclipnode;
int lastclipnode;
vec3_t clip_mins;
vec3_t clip_maxs;
} hull_t;
/*
==============================================================================
SPRITE MODELS
==============================================================================
*/
// FIXME: shorten these?
typedef struct mspriteframe_s
{
int width;
int height;
float up, down, left, right;
int gl_texturenum;
} mspriteframe_t;
typedef struct
{
int numframes;
float *intervals;
mspriteframe_t *frames[1];
} mspritegroup_t;
typedef struct
{
spriteframetype_t type;
mspriteframe_t *frameptr;
} mspriteframedesc_t;
typedef struct
{
int type;
int maxwidth;
int maxheight;
int numframes;
float beamlength; // remove?
void *cachespot; // remove?
mspriteframedesc_t frames[1];
} msprite_t;
/*
==============================================================================
ALIAS MODELS
Alias models are position independent, so the cache manager can move them.
==============================================================================
*/
typedef struct
{
int firstpose;
int numposes;
float interval;
trivertx_t bboxmin;
trivertx_t bboxmax;
int frame;
char name[16];
} maliasframedesc_t;
typedef struct
{
trivertx_t bboxmin;
trivertx_t bboxmax;
int frame;
} maliasgroupframedesc_t;
typedef struct
{
int numframes;
int intervals;
maliasgroupframedesc_t frames[1];
} maliasgroup_t;
typedef struct mtriangle_s {
int facesfront;
int vertindex[3];
} mtriangle_t;
#define MAX_SKINS 32
typedef struct {
int ident;
int version;
vec3_t scale;
vec3_t scale_origin;
float boundingradius;
vec3_t eyeposition;
int numskins;
int skinwidth;
int skinheight;
int numverts;
int numtris;
int numframes;
synctype_t synctype;
int flags;
float size;
int numposes;
int poseverts;
int posedata; // numposes*poseverts trivert_t
int commands; // gl command list with embedded s/t
int gl_texturenum[MAX_SKINS][4];
int texels[MAX_SKINS]; // only for player skins
maliasframedesc_t frames[1]; // variable sized
} aliashdr_t;
#define MAXALIASVERTS 2048
#define MAXALIASFRAMES 256
#define MAXALIASTRIS 2048
extern aliashdr_t *pheader;
extern stvert_t stverts[MAXALIASVERTS];
extern mtriangle_t triangles[MAXALIASTRIS];
extern trivertx_t *poseverts[MAXALIASFRAMES];
//===================================================================
//
// Whole model
//
typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;
#define EF_ROCKET 1 // leave a trail
#define EF_GRENADE 2 // leave a trail
#define EF_GIB 4 // leave a trail
#define EF_ROTATE 8 // rotate (bonus items)
#define EF_TRACER 16 // green split trail
#define EF_ZOMGIB 32 // small blood trail
#define EF_TRACER2 64 // orange split trail + rotate
#define EF_TRACER3 128 // purple trail
// some models are special
typedef enum
{
MOD_NORMAL,
MOD_PLAYER,
MOD_EYES,
MOD_FLAME,
MOD_THUNDERBOLT,
MOD_WEAPON,
MOD_LAVABALL,
MOD_SPIKE,
MOD_SHAMBLER,
MOD_SPR,
MOD_SPR32,
// MOD_GKEY,
// MOD_SKEY,
} modhint_t;
typedef struct model_s
{
char name[MAX_QPATH];
qboolean needload; // bmodels and sprites don't cache normally
modhint_t modhint;
modtype_t type;
int numframes;
synctype_t synctype;
int flags;
//
// volume occupied by the model graphics
//
vec3_t mins, maxs;
float radius;
//
// solid volume for clipping
//
qboolean clipbox;
vec3_t clipmins, clipmaxs;
//
// brush model
//
int firstmodelsurface, nummodelsurfaces;
int numsubmodels;
dmodel_t *submodels;
int numplanes;
mplane_t *planes;
int numleafs; // number of visible leafs, not counting 0
mleaf_t *leafs;
int numvertexes;
mvertex_t *vertexes;
int numedges;
medge_t *edges;
int numnodes;
mnode_t *nodes;
int numtexinfo;
mtexinfo_t *texinfo;
int numsurfaces;
msurface_t *surfaces;
int numsurfedges;
int *surfedges;
int numclipnodes;
dclipnode_t *clipnodes;
int nummarksurfaces;
msurface_t **marksurfaces;
hull_t hulls[MAX_MAP_HULLS];
int numtextures;
texture_t **textures;
byte *visdata;
byte *lightdata;
char *entities;
//
// additional model data
//
cache_user_t cache; // only access through Mod_Extradata
int bspversion; //Diabolickal HLBSP
} model_t;
//============================================================================
void Mod_Init (void);
void Mod_ClearAll (void);
model_t *Mod_ForName (char *name, qboolean crash);
void *Mod_Extradata (model_t *mod); // handles caching
void Mod_TouchModel (char *name);
mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model);
int GL_LoadTexture32 (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha); //Diabolickal HLBSP
void BuildGammaTable (float g);
int loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap); //Diabolickal TGA
#endif // __MODEL__

3040
source/ctr/gl/gl_qmb.c Normal file

File diff suppressed because it is too large Load diff

234
source/ctr/gl/gl_refrag.c Normal file
View file

@ -0,0 +1,234 @@
/*
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_efrag.c
#include "../../quakedef.h"
mnode_t *r_pefragtopnode;
//===========================================================================
/*
===============================================================================
ENTITY FRAGMENT FUNCTIONS
===============================================================================
*/
efrag_t **lastlink;
vec3_t r_emins, r_emaxs;
entity_t *r_addent;
/*
================
R_RemoveEfrags
Call when removing an object from the world or moving it to another position
================
*/
void R_RemoveEfrags (entity_t *ent)
{
efrag_t *ef, *old, *walk, **prev;
ef = ent->efrag;
while (ef)
{
prev = &ef->leaf->efrags;
while (1)
{
walk = *prev;
if (!walk)
break;
if (walk == ef)
{ // remove this fragment
*prev = ef->leafnext;
break;
}
else
prev = &walk->leafnext;
}
old = ef;
ef = ef->entnext;
// put it on the free list
old->entnext = cl.free_efrags;
cl.free_efrags = old;
}
ent->efrag = NULL;
}
/*
===================
R_SplitEntityOnNode
===================
*/
void R_SplitEntityOnNode (mnode_t *node)
{
efrag_t *ef;
mplane_t *splitplane;
mleaf_t *leaf;
int sides;
if (node->contents == CONTENTS_SOLID)
{
return;
}
// add an efrag if the node is a leaf
if ( node->contents < 0)
{
if (!r_pefragtopnode)
r_pefragtopnode = node;
leaf = (mleaf_t *)node;
// grab an efrag off the free list
ef = cl.free_efrags;
if (!ef)
{
Con_Printf ("Too many efrags!\n");
return; // no free fragments...
}
cl.free_efrags = cl.free_efrags->entnext;
ef->entity = r_addent;
// add the entity link
*lastlink = ef;
lastlink = &ef->entnext;
ef->entnext = NULL;
// set the leaf links
ef->leaf = leaf;
ef->leafnext = leaf->efrags;
leaf->efrags = ef;
return;
}
// NODE_MIXED
splitplane = node->plane;
sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
if (sides == 3)
{
// split on this plane
// if this is the first splitter of this bmodel, remember it
if (!r_pefragtopnode)
r_pefragtopnode = node;
}
// recurse down the contacted sides
if (sides & 1)
R_SplitEntityOnNode (node->children[0]);
if (sides & 2)
R_SplitEntityOnNode (node->children[1]);
}
/*
===========
R_AddEfrags
===========
*/
void R_AddEfrags (entity_t *ent)
{
model_t *entmodel;
int i;
if (!ent->model)
return;
r_addent = ent;
lastlink = &ent->efrag;
r_pefragtopnode = NULL;
entmodel = ent->model;
for (i=0 ; i<3 ; i++)
{
r_emins[i] = ent->origin[i] + entmodel->mins[i];
r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
}
R_SplitEntityOnNode (cl.worldmodel->nodes);
ent->topnode = r_pefragtopnode;
}
/*
================
R_StoreEfrags
// FIXME: a lot of this goes away with edge-based
================
*/
void R_StoreEfrags (efrag_t **ppefrag)
{
entity_t *pent;
model_t *clmodel;
efrag_t *pefrag;
while ((pefrag = *ppefrag) != NULL)
{
pent = pefrag->entity;
clmodel = pent->model;
switch (clmodel->type)
{
case mod_alias:
case mod_brush:
case mod_sprite:
pent = pefrag->entity;
if ((pent->visframe != r_framecount) &&
(cl_numvisedicts < MAX_VISEDICTS))
{
cl_visedicts[cl_numvisedicts++] = pent;
// mark that we've recorded this entity for this frame
pent->visframe = r_framecount;
}
ppefrag = &pefrag->leafnext;
break;
default:
Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
}
}
}

399
source/ctr/gl/gl_rlight.c Normal file
View file

@ -0,0 +1,399 @@
/*
Copyright (C) 1996-2001 Id Software, Inc.
Copyright (C) 2002-2009 John Fitzgibbons and others
Copyright (C) 2010-2014 QuakeSpasm developers
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"
int r_dlightframecount;
extern cvar_t r_flatlightstyles; //johnfitz
/*
==================
R_AnimateLight
==================
*/
void R_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;
}
//johnfitz -- r_flatlightstyles
if (r_flatlightstyles.value == 2)
k = cl_lightstyle[j].peak - 'a';
else if (r_flatlightstyles.value == 1)
k = cl_lightstyle[j].average - 'a';
else
{
k = i % cl_lightstyle[j].length;
k = cl_lightstyle[j].map[k] - 'a';
}
d_lightstylevalue[j] = k*22;
//johnfitz
}
}
/*
=============================================================================
DYNAMIC LIGHTS BLEND RENDERING (gl_flashblend 1)
=============================================================================
*/
void AddLightBlend (float r, float g, float b, float a2)
{
float a;
v_blend[3] = a = v_blend[3] + a2*(1-v_blend[3]);
a2 = a2/a;
v_blend[0] = v_blend[1]*(1-a2) + r*a2;
v_blend[1] = v_blend[1]*(1-a2) + g*a2;
v_blend[2] = v_blend[2]*(1-a2) + b*a2;
}
void R_RenderDlight (dlight_t *light)
{
#if 0
int i, j;
float a;
vec3_t v;
float rad;
rad = light->radius * 0.35;
VectorSubtract (light->origin, r_origin, v);
if (VectorLength (v) < rad)
{ // view is inside the dlight
AddLightBlend (1, 0.5, 0, light->radius * 0.0003);
return;
}
glBegin (GL_TRIANGLE_FAN);
//glColor4f(lightcolor[0]/255, lightcolor[1]/255, lightcolor[2]/255, 1.0f);
glColor4f (light->color[0]*0.2f,light->color[1]*0.2f,light->color[2]*0.2f, 1.0f);
//glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
for (i=0 ; i<3 ; i++)
v[i] = light->origin[i] - vpn[i]*rad;
glVertex3fv (v);
//glColor3f (0,0,0);
for (i=16 ; i>=0 ; i--)
{
a = i/16.0 * M_PI*2;
for (j=0 ; j<3 ; j++)
v[j] = light->origin[j] + vright[j]*cos(a)*rad
+ vup[j]*sin(a)*rad;
glVertex3fv (v);
}
glEnd ();
#endif
}
/*
=============
R_RenderDlights
=============
*/
void R_RenderDlights (void)
{
#if 0
int i;
dlight_t *l;
if (!gl_flashblend.value)
return;
r_dlightframecount = r_framecount + 1; // because the count hasn't
// advanced yet for this frame
glDepthMask (GL_FALSE);
glDisable (GL_TEXTURE_2D);
glShadeModel (GL_SMOOTH);
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE);
l = cl_dlights;
for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
{
if (l->die < cl.time || !l->radius)
continue;
R_RenderDlight (l);
}
glColor3f (1,1,1);
glDisable (GL_BLEND);
glEnable (GL_TEXTURE_2D);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask (GL_TRUE);
#endif
}
/*
=============================================================================
DYNAMIC LIGHTS
=============================================================================
*/
/*
=============
R_MarkLights -- johnfitz -- rewritten to use LordHavoc's lighting speedup
=============
*/
void R_MarkLights (dlight_t *light, int num, mnode_t *node)
{
mplane_t *splitplane;
msurface_t *surf;
vec3_t impact;
float dist, l, maxdist;
int i, j, s, t;
start:
if (node->contents < 0)
return;
splitplane = node->plane;
if (splitplane->type < 3)
dist = light->origin[splitplane->type] - splitplane->dist;
else
dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
if (dist > light->radius)
{
node = node->children[0];
goto start;
}
if (dist < -light->radius)
{
node = node->children[1];
goto start;
}
maxdist = light->radius*light->radius;
// mark the polygons
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
for (j=0 ; j<3 ; j++)
impact[j] = light->origin[j] - surf->plane->normal[j]*dist;
// clamp center of light to corner and check brightness
l = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
s = l+0.5;if (s < 0) s = 0;else if (s > surf->extents[0]) s = surf->extents[0];
s = l - s;
l = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
t = l+0.5;if (t < 0) t = 0;else if (t > surf->extents[1]) t = surf->extents[1];
t = l - t;
// compare to minimum light
if ((s*s+t*t+dist*dist) < maxdist)
{
if (surf->dlightframe != r_dlightframecount) // not dynamic until now
{
surf->dlightbits[num >> 5] = 1U << (num & 31);
surf->dlightframe = r_dlightframecount;
}
else // already dynamic
surf->dlightbits[num >> 5] |= 1U << (num & 31);
}
}
if (node->children[0]->contents >= 0)
R_MarkLights (light, num, node->children[0]);
if (node->children[1]->contents >= 0)
R_MarkLights (light, num, node->children[1]);
}
/*
=============
R_PushDlights
=============
*/
void R_PushDlights (void)
{
int i;
dlight_t *l;
r_dlightframecount = r_framecount + 1; // because the count hasn't
// advanced yet for this frame
l = cl_dlights;
for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
{
if (l->die < cl.time || !l->radius)
continue;
R_MarkLights (l, i, cl.worldmodel->nodes);
}
}
/*
=============================================================================
LIGHT SAMPLING
=============================================================================
*/
mplane_t *lightplane;
vec3_t lightspot;
vec3_t lightcolor; //johnfitz -- lit support via lordhavoc
/*
=============
RecursiveLightPoint -- johnfitz -- replaced entire function for lit support via lordhavoc
=============
*/
int RecursiveLightPoint (vec3_t color, mnode_t *node, vec3_t start, vec3_t end)
{
float front, back, frac;
vec3_t mid;
loc0:
if (node->contents < 0)
return false; // didn't hit anything
// calculate mid point
if (node->plane->type < 3)
{
front = start[node->plane->type] - node->plane->dist;
back = end[node->plane->type] - node->plane->dist;
}
else
{
front = DotProduct(start, node->plane->normal) - node->plane->dist;
back = DotProduct(end, node->plane->normal) - node->plane->dist;
}
// LordHavoc: optimized recursion
if ((back < 0) == (front < 0))
// return RecursiveLightPoint (color, node->children[front < 0], start, end);
{
node = node->children[front < 0];
goto loc0;
}
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
if (RecursiveLightPoint (color, node->children[front < 0], start, mid))
return true; // hit something
else
{
int i, ds, dt;
msurface_t *surf;
// check for impact on this node
VectorCopy (mid, lightspot);
lightplane = node->plane;
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i = 0;i < node->numsurfaces;i++, surf++)
{
if (surf->flags & SURF_DRAWTILED)
continue; // no lightmaps
// ericw -- added double casts to force 64-bit precision.
// Without them the zombie at the start of jam3_ericw.bsp was
// incorrectly being lit up in SSE builds.
ds = (int) ((double) DoublePrecisionDotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
dt = (int) ((double) DoublePrecisionDotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
continue;
ds -= surf->texturemins[0];
dt -= surf->texturemins[1];
if (ds > surf->extents[0] || dt > surf->extents[1])
continue;
if (surf->samples)
{
// LordHavoc: enhanced to interpolate lighting
byte *lightmap;
int maps, line3, dsfrac = ds & 15, dtfrac = dt & 15, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0;
float scale;
line3 = ((surf->extents[0]>>4)+1)*3;
lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color
for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
{
scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;
r00 += (float) lightmap[ 0] * scale;g00 += (float) lightmap[ 1] * scale;b00 += (float) lightmap[2] * scale;
r01 += (float) lightmap[ 3] * scale;g01 += (float) lightmap[ 4] * scale;b01 += (float) lightmap[5] * scale;
r10 += (float) lightmap[line3+0] * scale;g10 += (float) lightmap[line3+1] * scale;b10 += (float) lightmap[line3+2] * scale;
r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale;
lightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
}
color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)));
color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)));
color[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)));
}
return true; // success
}
// go down back side
return RecursiveLightPoint (color, node->children[front >= 0], mid, end);
}
}
/*
=============
R_LightPoint -- johnfitz -- replaced entire function for lit support via lordhavoc
=============
*/
int R_LightPoint (vec3_t p)
{
vec3_t end;
if (!cl.worldmodel->lightdata)
{
lightcolor[0] = lightcolor[1] = lightcolor[2] = 255;
return 255;
}
end[0] = p[0];
end[1] = p[1];
end[2] = p[2] - 8192; //johnfitz -- was 2048
lightcolor[0] = lightcolor[1] = lightcolor[2] = 0;
RecursiveLightPoint (lightcolor, cl.worldmodel->nodes, p, end);
return ((lightcolor[0] + lightcolor[1] + lightcolor[2]) * (1.0f / 3.0f));
}

1882
source/ctr/gl/gl_rmain.c Normal file

File diff suppressed because it is too large Load diff

516
source/ctr/gl/gl_rmisc.c Normal file
View file

@ -0,0 +1,516 @@
/*
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"
extern cvar_t r_flatlightstyles;
int decal_blood1, decal_blood2, decal_blood3, decal_q3blood, decal_burn, decal_mark, decal_glow;
int zombie_skins[4];
/*
==================
R_InitOtherTextures
==================
*/
void R_InitOtherTextures (void)
{
//static decals
decal_blood1 = loadtextureimage ("textures/decals/blood_splat01", 0, 0, qfalse, qtrue);
decal_blood2 = loadtextureimage ("textures/decals/blood_splat02", 0, 0, qfalse, qtrue);
decal_blood3 = loadtextureimage ("textures/decals/blood_splat03", 0, 0, qfalse, qtrue);
decal_q3blood = loadtextureimage ("textures/decals/blood_stain", 0, 0, qfalse, qtrue);
decal_burn = loadtextureimage ("textures/decals/explo_burn01", 0, 0, qfalse, qtrue);
decal_mark = loadtextureimage ("textures/decals/particle_burn01", 0, 0, qfalse, qtrue);
decal_glow = loadtextureimage ("textures/decals/glow2", 0, 0, qfalse, qtrue);
// external zombie skins
zombie_skins[0] = loadtextureimage ("models/ai/zfull.mdl_0", 0, 0, qtrue, qfalse);
zombie_skins[1] = loadtextureimage ("models/ai/zfull.mdl_1", 0, 0, qtrue, qfalse);
zombie_skins[2] = loadtextureimage ("models/ai/zfull.mdl_2", 0, 0, qtrue, qfalse);
zombie_skins[3] = loadtextureimage ("models/ai/zfull.mdl_3", 0, 0, qtrue, qfalse);
}
/*
==================
R_InitTextures
==================
*/
void R_InitTextures (void)
{
int x,y, m;
byte *dest;
// create a simple checkerboard texture for the default
r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture");
r_notexture_mip->width = r_notexture_mip->height = 16;
r_notexture_mip->offsets[0] = sizeof(texture_t);
r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
for (m=0 ; m<4 ; m++)
{
dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
for (y=0 ; y< (16>>m) ; y++)
for (x=0 ; x< (16>>m) ; x++)
{
if ( (y< (8>>m) ) ^ (x< (8>>m) ) )
*dest++ = 0;
else
*dest++ = 0xff;
}
}
}
byte dottexture[8][8] =
{
{0,1,1,0,0,0,0,0},
{1,1,1,1,0,0,0,0},
{1,1,1,1,0,0,0,0},
{0,1,1,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
};
void R_InitParticleTexture (void)
{
int x,y;
byte data[8][8][4];
//
// particle texture
//
particletexture = texture_extension_number++;
GL_Bind(particletexture);
for (x=0 ; x<8 ; x++)
{
for (y=0 ; y<8 ; y++)
{
data[y][x][0] = 255;
data[y][x][1] = 255;
data[y][x][2] = 255;
data[y][x][3] = dottexture[x][y]*255;
}
}
glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
/*
===============
R_Envmap_f
Grab six views for environment mapping tests
===============
*/
void R_Envmap_f (void)
{
byte buffer[256*256*4];
char name[1024];
glDrawBuffer (GL_FRONT);
glReadBuffer (GL_FRONT);
envmap = true;
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = 256;
r_refdef.vrect.height = 256;
r_refdef.viewangles[0] = 0;
r_refdef.viewangles[1] = 0;
r_refdef.viewangles[2] = 0;
GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
R_RenderView ();
glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
COM_WriteFile ("env0.rgb", buffer, sizeof(buffer));
r_refdef.viewangles[1] = 90;
GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
R_RenderView ();
glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
COM_WriteFile ("env1.rgb", buffer, sizeof(buffer));
r_refdef.viewangles[1] = 180;
GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
R_RenderView ();
glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
COM_WriteFile ("env2.rgb", buffer, sizeof(buffer));
r_refdef.viewangles[1] = 270;
GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
R_RenderView ();
glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
COM_WriteFile ("env3.rgb", buffer, sizeof(buffer));
r_refdef.viewangles[0] = -90;
r_refdef.viewangles[1] = 0;
GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
R_RenderView ();
glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
COM_WriteFile ("env4.rgb", buffer, sizeof(buffer));
r_refdef.viewangles[0] = 90;
r_refdef.viewangles[1] = 0;
GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
R_RenderView ();
glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
COM_WriteFile ("env5.rgb", buffer, sizeof(buffer));
envmap = false;
glDrawBuffer (GL_BACK);
glReadBuffer (GL_BACK);
GL_EndRendering ();
}
/*
===============
R_Init
===============
*/
extern bool new3ds_flag;
void R_Init (void)
{
extern byte *hunk_base;
extern cvar_t gl_finish;
Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
Cmd_AddCommand ("envmap", R_Envmap_f);
Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
Cvar_RegisterVariable (&r_norefresh);
Cvar_RegisterVariable (&r_lightmap);
Cvar_RegisterVariable (&r_fullbright);
Cvar_RegisterVariable (&r_drawentities);
Cvar_RegisterVariable (&r_drawviewmodel);
Cvar_RegisterVariable (&r_shadows);
Cvar_RegisterVariable (&r_mirroralpha);
Cvar_RegisterVariable (&r_wateralpha);
Cvar_RegisterVariable (&r_dynamic);
Cvar_RegisterVariable (&r_novis);
Cvar_RegisterVariable (&r_speeds);
Cvar_RegisterVariable (&r_farclip);
Cvar_RegisterVariable (&gl_finish);
Cvar_RegisterVariable (&gl_clear);
Cvar_RegisterVariable (&gl_texsort);
Cvar_SetValue("gl_clear", 1);
if (gl_mtexable)
Cvar_SetValue ("gl_texsort", 0.0);
Cvar_RegisterVariable (&gl_cull);
Cvar_RegisterVariable (&gl_smoothmodels);
Cvar_RegisterVariable (&gl_affinemodels);
Cvar_RegisterVariable (&gl_polyblend);
Cvar_RegisterVariable (&gl_flashblend);
Cvar_RegisterVariable (&gl_playermip);
Cvar_RegisterVariable (&gl_nocolors);
Cvar_RegisterVariable (&gl_keeptjunctions);
Cvar_RegisterVariable (&gl_reporttjunctions);
Cvar_RegisterVariable (&gl_doubleeyes);
Cvar_RegisterVariable (&r_explosiontype);
Cvar_RegisterVariable (&r_laserpoint);
Cvar_RegisterVariable (&r_part_explosions);
Cvar_RegisterVariable (&r_part_trails);
Cvar_RegisterVariable (&r_part_sparks);
Cvar_RegisterVariable (&r_part_gunshots);
Cvar_RegisterVariable (&r_part_blood);
Cvar_RegisterVariable (&r_part_telesplash);
Cvar_RegisterVariable (&r_part_blobs);
Cvar_RegisterVariable (&r_part_lavasplash);
Cvar_RegisterVariable (&r_part_flames);
Cvar_RegisterVariable (&r_part_lightning);
Cvar_RegisterVariable (&r_part_flies);
Cvar_RegisterVariable (&r_part_muzzleflash);
Cvar_RegisterVariable (&r_flametype);
Cvar_RegisterVariable (&r_model_brightness);
Cvar_RegisterVariable (&r_skyfog);
Cvar_RegisterVariable (&r_flatlightstyles);
R_InitParticles ();
R_InitOtherTextures ();
R_InitParticleTexture ();
Sky_Init (); //johnfitz
Fog_Init (); //johnfitz
#ifdef GLTEST
Test_Init ();
#endif
playertextures = texture_extension_number;
texture_extension_number += 16;
if (new3ds_flag == true)
Cvar_SetValue("r_dynamic", 1);
else
Cvar_SetValue("r_dynamic", 0);
}
/*
===============
R_TranslatePlayerSkin
Translates a skin texture by the per-player color lookup
===============
*/
void R_TranslatePlayerSkin (int playernum)
{
int top, bottom;
byte translate[256];
unsigned translate32[256];
int i, j, s;
model_t *model;
aliashdr_t *paliashdr;
byte *original;
unsigned pixels[512*256], *out;
unsigned scaled_width, scaled_height;
int inwidth, inheight;
byte *inrow;
unsigned frac, fracstep;
extern byte **player_8bit_texels_tbl;
GL_DisableMultitexture();
top = 0xf0;
bottom = (15)<<4;
for (i=0 ; i<256 ; i++)
translate[i] = i;
for (i=0 ; i<16 ; i++)
{
if (top < 128) // the artists made some backwards ranges. sigh.
translate[TOP_RANGE+i] = top+i;
else
translate[TOP_RANGE+i] = top+15-i;
if (bottom < 128)
translate[BOTTOM_RANGE+i] = bottom+i;
else
translate[BOTTOM_RANGE+i] = bottom+15-i;
}
//
// locate the original skin pixels
//
currententity = &cl_entities[1+playernum];
model = currententity->model;
if (!model)
return; // player doesn't have a model yet
if (model->type != mod_alias)
return; // only translate skins on alias models
paliashdr = (aliashdr_t *)Mod_Extradata (model);
s = paliashdr->skinwidth * paliashdr->skinheight;
if (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins) {
Con_Printf("(%d): Invalid player skin #%d\n", playernum, currententity->skinnum);
original = (byte *)paliashdr + paliashdr->texels[0];
} else
original = (byte *)paliashdr + paliashdr->texels[currententity->skinnum];
if (s & 3)
Sys_Error ("R_TranslateSkin: s&3");
inwidth = paliashdr->skinwidth;
inheight = paliashdr->skinheight;
// because this happens during gameplay, do it fast
// instead of sending it through gl_upload 8
GL_Bind(playertextures + playernum);
#if 0
byte translated[320*200];
for (i=0 ; i<s ; i+=4)
{
translated[i] = translate[original[i]];
translated[i+1] = translate[original[i+1]];
translated[i+2] = translate[original[i+2]];
translated[i+3] = translate[original[i+3]];
}
// don't mipmap these, because it takes too long
GL_Upload8 (translated, paliashdr->skinwidth, paliashdr->skinheight, false, false, true);
#else
scaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512;
scaled_height = gl_max_size.value < 256 ? gl_max_size.value : 256;
// allow users to crunch sizes down even more if they want
scaled_width >>= (int)gl_playermip.value;
scaled_height >>= (int)gl_playermip.value;
if (VID_Is8bit()) { // 8bit texture upload
byte *out2;
out2 = (byte *)pixels;
memset(pixels, 0, sizeof(pixels));
fracstep = inwidth*0x10000/scaled_width;
for (i=0 ; i<scaled_height ; i++, out2 += scaled_width)
{
inrow = original + inwidth*(i*inheight/scaled_height);
frac = fracstep >> 1;
for (j=0 ; j<scaled_width ; j+=4)
{
out2[j] = translate[inrow[frac>>16]];
frac += fracstep;
out2[j+1] = translate[inrow[frac>>16]];
frac += fracstep;
out2[j+2] = translate[inrow[frac>>16]];
frac += fracstep;
out2[j+3] = translate[inrow[frac>>16]];
frac += fracstep;
}
}
GL_Upload8_EXT ((byte *)pixels, scaled_width, scaled_height, false, false);
return;
}
for (i=0 ; i<256 ; i++)
translate32[i] = d_8to24table[translate[i]];
out = pixels;
fracstep = inwidth*0x10000/scaled_width;
for (i=0 ; i<scaled_height ; i++, out += scaled_width)
{
inrow = original + inwidth*(i*inheight/scaled_height);
frac = fracstep >> 1;
for (j=0 ; j<scaled_width ; j+=4)
{
out[j] = translate32[inrow[frac>>16]];
frac += fracstep;
out[j+1] = translate32[inrow[frac>>16]];
frac += fracstep;
out[j+2] = translate32[inrow[frac>>16]];
frac += fracstep;
out[j+3] = translate32[inrow[frac>>16]];
frac += fracstep;
}
}
glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#endif
}
/*
===============
R_NewMap
===============
*/
void R_NewMap (void)
{
int i;
for (i=0 ; i<256 ; i++)
d_lightstylevalue[i] = 264; // normal light value
memset (&r_worldentity, 0, sizeof(r_worldentity));
r_worldentity.model = cl.worldmodel;
// clear out efrags in case the level hasn't been reloaded
// FIXME: is this one short?
for (i=0 ; i<cl.worldmodel->numleafs ; i++)
cl.worldmodel->leafs[i].efrags = NULL;
r_viewleaf = NULL;
R_ClearParticles ();
GL_BuildLightmaps ();
Sky_NewMap (); //johnfitz -- skybox in worldspawn
Fog_NewMap (); // johnfitz -- global fog in worldspawn
// identify sky texture
skytexturenum = -1;
mirrortexturenum = -1;
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
{
if (!cl.worldmodel->textures[i])
continue;
if (!strncmp(cl.worldmodel->textures[i]->name,"sky",3) )
skytexturenum = i;
if (!strncmp(cl.worldmodel->textures[i]->name,"window02_1",10) )
mirrortexturenum = i;
cl.worldmodel->textures[i]->texturechain = NULL;
}
//R_LoadSkys ();
}
/*
====================
R_TimeRefresh_f
For program optimization
====================
*/
void R_TimeRefresh_f (void)
{
int i;
float start, stop, time;
int startangle;
vrect_t vr;
glDrawBuffer (GL_FRONT);
glFinish ();
start = Sys_FloatTime ();
for (i=0 ; i<128 ; i++)
{
r_refdef.viewangles[1] = i/128.0*360.0;
R_RenderView ();
}
glFinish ();
stop = Sys_FloatTime ();
time = stop-start;
Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
glDrawBuffer (GL_BACK);
GL_EndRendering ();
}
void D_FlushCaches (void)
{
}

1814
source/ctr/gl/gl_rsurf.c Normal file

File diff suppressed because it is too large Load diff

1649
source/ctr/gl/gl_screen.c Normal file

File diff suppressed because it is too large Load diff

182
source/ctr/gl/gl_test.c Normal file
View file

@ -0,0 +1,182 @@
/*
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.
*/
#include "../../quakedef.h"
#ifdef GLTEST
typedef struct
{
plane_t *plane;
vec3_t origin;
vec3_t normal;
vec3_t up;
vec3_t right;
vec3_t reflect;
float length;
} puff_t;
#define MAX_PUFFS 64
puff_t puffs[MAX_PUFFS];
void Test_Init (void)
{
}
plane_t junk;
plane_t *HitPlane (vec3_t start, vec3_t end)
{
trace_t trace;
// fill in a default trace
memset (&trace, 0, sizeof(trace_t));
trace.fraction = 1;
trace.allsolid = true;
VectorCopy (end, trace.endpos);
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);
junk = trace.plane;
return &junk;
}
void Test_Spawn (vec3_t origin)
{
int i;
puff_t *p;
vec3_t temp;
vec3_t normal;
vec3_t incoming;
plane_t *plane;
float d;
for (i=0,p=puffs ; i<MAX_PUFFS ; i++,p++)
{
if (p->length <= 0)
break;
}
if (i == MAX_PUFFS)
return;
VectorSubtract (r_refdef.vieworg, origin, incoming);
VectorSubtract (origin, incoming, temp);
plane = HitPlane (r_refdef.vieworg, temp);
VectorNormalize (incoming);
d = DotProduct (incoming, plane->normal);
VectorSubtract (vec3_origin, incoming, p->reflect);
VectorMA (p->reflect, d*2, plane->normal, p->reflect);
VectorCopy (origin, p->origin);
VectorCopy (plane->normal, p->normal);
CrossProduct (incoming, p->normal, p->up);
CrossProduct (p->up, p->normal, p->right);
p->length = 8;
}
void DrawPuff (puff_t *p)
{
vec3_t pts[2][3];
int i, j;
float s, d;
for (i=0 ; i<2 ; i++)
{
if (i == 1)
{
s = 6;
d = p->length;
}
else
{
s = 2;
d = 0;
}
for (j=0 ; j<3 ; j++)
{
pts[i][0][j] = p->origin[j] + p->up[j]*s + p->reflect[j]*d;
pts[i][1][j] = p->origin[j] + p->right[j]*s + p->reflect[j]*d;
pts[i][2][j] = p->origin[j] + -p->right[j]*s + p->reflect[j]*d;
}
}
glColor3f (1, 0, 0);
#if 0
glBegin (GL_LINES);
glVertex3fv (p->origin);
glVertex3f (p->origin[0] + p->length*p->reflect[0],
p->origin[1] + p->length*p->reflect[1],
p->origin[2] + p->length*p->reflect[2]);
glVertex3fv (pts[0][0]);
glVertex3fv (pts[1][0]);
glVertex3fv (pts[0][1]);
glVertex3fv (pts[1][1]);
glVertex3fv (pts[0][2]);
glVertex3fv (pts[1][2]);
glEnd ();
#endif
glBegin (GL_QUADS);
for (i=0 ; i<3 ; i++)
{
j = (i+1)%3;
glVertex3fv (pts[0][j]);
glVertex3fv (pts[1][j]);
glVertex3fv (pts[1][i]);
glVertex3fv (pts[0][i]);
}
glEnd ();
glBegin (GL_TRIANGLES);
glVertex3fv (pts[1][0]);
glVertex3fv (pts[1][1]);
glVertex3fv (pts[1][2]);
glEnd ();
p->length -= host_frametime*2;
}
void Test_Draw (void)
{
int i;
puff_t *p;
for (i=0, p=puffs ; i<MAX_PUFFS ; i++,p++)
{
if (p->length > 0)
DrawPuff (p);
}
}
#endif

252
source/ctr/gl/gl_vidctr.c Normal file
View file

@ -0,0 +1,252 @@
/*
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.
*/
#include <3ds.h>
#include <GL/picaGL.h>
#include "../../quakedef.h"
unsigned d_8to24table[256];
unsigned char d_15to8table[65536];
int texture_mode = GL_LINEAR;
int texture_extension_number = 1;
float gldepthmin, gldepthmax;
cvar_t gl_ztrick = {"gl_ztrick","0"};
const char *gl_vendor;
const char *gl_renderer;
const char *gl_version;
const char *gl_extensions;
static float vid_gamma = 1.0;
qboolean is8bit = false;
qboolean isPermedia = true;
qboolean gl_mtexable = false;
/*
===============
GL_Init
===============
*/
void GL_Init (void)
{
pglInitEx(0x040000, 0x100000);
gl_vendor = glGetString (GL_VENDOR);
gl_renderer = glGetString (GL_RENDERER);
gl_version = glGetString (GL_VERSION);
gl_extensions = glGetString (GL_EXTENSIONS);
glClearDepth (1.0f);
glClearColor ((float)(16/255),(float)(32/255),(float)(64/255),1);
glCullFace(GL_FRONT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.666);
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
glShadeModel (GL_FLAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glClear(GL_COLOR_BUFFER_BIT);
}
void GL_BeginRendering (int *x, int *y, int *width, int *height)
{
*x = *y = 0;
*width = 400;
*height = 240;
}
void GL_EndRendering (void)
{
// naievil -- this requies the new version of picagl to be used properly
//glFinish();
pglSwapBuffersEx(1,0);
}
void VID_SetPalette (unsigned char *palette)
{
byte *pal;
unsigned r,g,b;
unsigned v;
int r1,g1,b1;
int j,k,l,m;
unsigned short i;
unsigned *table;
FILE *f;
char s[255];
int dist, bestdist;
//
// 8 8 8 encoding
//
pal = palette;
table = d_8to24table;
for (i=0 ; i<256 ; i++)
{
r = pal[0];
g = pal[1];
b = pal[2];
pal += 3;
v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
*table++ = v;
}
d_8to24table[255] &= 0xffffff; // 255 is transparent
// JACK: 3D distance calcs - k is last closest, l is the distance.
for (i=0; i < (1<<15); i++) {
/* Maps
000000000000000
000000000011111 = Red = 0x1F
000001111100000 = Blue = 0x03E0
111110000000000 = Grn = 0x7C00
*/
r = ((i & 0x1F) << 3)+4;
g = ((i & 0x03E0) >> 2)+4;
b = ((i & 0x7C00) >> 7)+4;
pal = (unsigned char *)d_8to24table;
for (v=0,k=0,bestdist=10000*10000; v<256; v++,pal+=4) {
r1 = (int)r - (int)pal[0];
g1 = (int)g - (int)pal[1];
b1 = (int)b - (int)pal[2];
dist = (r1*r1)+(g1*g1)+(b1*b1);
if (dist < bestdist) {
k=v;
bestdist = dist;
}
}
d_15to8table[i]=k;
}
}
void VID_ShiftPalette (unsigned char *palette)
{
//VID_SetPalette(palette);
}
qboolean VID_Is8bit(void)
{
return is8bit;
}
static void Check_Gamma (unsigned char *pal)
{
float f, inf;
unsigned char palette[768];
int i;
if ((i = COM_CheckParm("-gamma")) == 0)
vid_gamma = 0.7;
else
vid_gamma = Q_atof(com_argv[i+1]);
for (i=0 ; i<768 ; i++)
{
f = pow ( (pal[i]+1)/256.0 , vid_gamma );
inf = f*255 + 0.5;
if (inf < 0)
inf = 0;
if (inf > 255)
inf = 255;
palette[i] = inf;
}
memcpy (pal, palette, sizeof(palette));
BuildGammaTable (vid_gamma); //Diabolickal HLBSP
}
void VID_Init (unsigned char *palette)
{
int i;
char gldir[MAX_OSPATH];
int width = 400;
int height = 240;
Cvar_RegisterVariable (&gl_ztrick);
vid.maxwarpwidth = width;
vid.maxwarpheight = height;
vid.colormap = host_colormap;
vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
vid.conwidth = 320;
vid.conwidth &= 0xfff8; // make it a multiple of eight
if (vid.conwidth < 320)
vid.conwidth = 320;
// pick a conheight that matches with correct aspect
vid.conheight = vid.conwidth*3 / 4;
if ((i = COM_CheckParm("-conheight")) != 0)
vid.conheight = Q_atoi(com_argv[i+1]);
if (vid.conheight < 200)
vid.conheight = 200;
if (vid.conheight > height)
vid.conheight = height;
if (vid.conwidth > width)
vid.conwidth = width;
vid.width = 400;
vid.height = 240;
vid.aspect = ((float)vid.height / (float)vid.width) *
(320.0 / 240.0);
vid.numpages = 2;
GL_Init();
sprintf (gldir, "%s/glquake", com_gamedir);
Sys_mkdir (gldir);
Check_Gamma(palette);
VID_SetPalette(palette);
Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
vid.recalc_refdef = 1; // force a surface cache flush
}
void VID_Shutdown (void)
{
}
void VID_Update (vrect_t *rects)
{
}

785
source/ctr/gl/gl_warp.c Normal file
View file

@ -0,0 +1,785 @@
/*
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.
*/
// gl_warp.c -- sky and water polygons
#include "../../quakedef.h"
extern model_t *loadmodel;
int skytexturenum;
int solidskytexture;
int alphaskytexture;
float speedscale; // for top sky and bottom sky
int skytexorder[5] = {0,2,1,3,4};
int skyimage[5]; // Where sky images are stored
char skybox_name[32] = ""; //name of current skybox, or "" if no skybox
// cut off down for half skybox
char *suf[5] = {"rt", "bk", "lf", "ft", "up" };
msurface_t *warpface;
extern cvar_t gl_subdivide_size;
void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
{
int i, j;
float *v;
mins[0] = mins[1] = mins[2] = 9999;
maxs[0] = maxs[1] = maxs[2] = -9999;
v = verts;
for (i=0 ; i<numverts ; i++)
for (j=0 ; j<3 ; j++, v++)
{
if (*v < mins[j])
mins[j] = *v;
if (*v > maxs[j])
maxs[j] = *v;
}
}
void SubdividePolygon (int numverts, float *verts)
{
int i, j, k;
vec3_t mins, maxs;
float m;
float *v;
vec3_t front[64], back[64];
int f, b;
float dist[64];
float frac;
glpoly_t *poly;
float s, t;
if (numverts > 60)
Sys_Error ("numverts = %i", numverts);
BoundPoly (numverts, verts, mins, maxs);
for (i=0 ; i<3 ; i++)
{
m = (mins[i] + maxs[i]) * 0.5;
m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5);
if (maxs[i] - m < 8)
continue;
if (m - mins[i] < 8)
continue;
// cut it
v = verts + i;
for (j=0 ; j<numverts ; j++, v+= 3)
dist[j] = *v - m;
// wrap cases
dist[j] = dist[0];
v-=i;
VectorCopy (verts, v);
f = b = 0;
v = verts;
for (j=0 ; j<numverts ; j++, v+= 3)
{
if (dist[j] >= 0)
{
VectorCopy (v, front[f]);
f++;
}
if (dist[j] <= 0)
{
VectorCopy (v, back[b]);
b++;
}
if (dist[j] == 0 || dist[j+1] == 0)
continue;
if ( (dist[j] > 0) != (dist[j+1] > 0) )
{
// clip point
frac = dist[j] / (dist[j] - dist[j+1]);
for (k=0 ; k<3 ; k++)
front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);
f++;
b++;
}
}
SubdividePolygon (f, front[0]);
SubdividePolygon (b, back[0]);
return;
}
poly = Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float));
poly->next = warpface->polys;
warpface->polys = poly;
poly->numverts = numverts;
for (i=0 ; i<numverts ; i++, verts+= 3)
{
VectorCopy (verts, poly->verts[i]);
s = DotProduct (verts, warpface->texinfo->vecs[0]);
t = DotProduct (verts, warpface->texinfo->vecs[1]);
poly->verts[i][3] = s;
poly->verts[i][4] = t;
}
}
/*
================
GL_SubdivideSurface
Breaks a polygon up along axial 64 unit
boundaries so that turbulent and sky warps
can be done reasonably.
================
*/
void GL_SubdivideSurface (msurface_t *fa)
{
vec3_t verts[64];
int numverts;
int i;
int lindex;
float *vec;
texture_t *t;
warpface = fa;
//
// convert edges back to a normal polygon
//
numverts = 0;
for (i=0 ; i<fa->numedges ; i++)
{
lindex = loadmodel->surfedges[fa->firstedge + i];
if (lindex > 0)
vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
else
vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
VectorCopy (vec, verts[numverts]);
numverts++;
}
SubdividePolygon (numverts, verts[0]);
}
//=========================================================
// speed up sin calculations - Ed
float turbsin[] =
{
#include "gl_warp_sin.h"
};
#define TURBSCALE (256.0 / (2 * M_PI))
/*
=============
EmitWaterPolys
Does a water warp on the pre-fragmented glpoly_t chain
=============
*/
void EmitWaterPolys (msurface_t *fa)
{
glpoly_t *p;
float *v;
int i;
float s, t, os, ot;
for (p=fa->polys ; p ; p=p->next)
{
glBegin (GL_POLYGON);
for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
{
os = v[3];
ot = v[4];
s = os + turbsin[(int)((ot*0.125+realtime) * TURBSCALE) & 255];
s *= (1.0/64);
t = ot + turbsin[(int)((os*0.125+realtime) * TURBSCALE) & 255];
t *= (1.0/64);
glTexCoord2f (s, t);
glVertex3fv (v);
}
glEnd ();
}
}
/*
=============
EmitSkyPolys
=============
*/
void EmitSkyPolys (msurface_t *fa)
{
glpoly_t *p;
float *v;
int i;
float s, t;
vec3_t dir;
float length;
for (p=fa->polys ; p ; p=p->next)
{
glBegin (GL_POLYGON);
for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)
{
VectorSubtract (v, r_origin, dir);
dir[2] *= 3; // flatten the sphere
length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
length = sqrt (length);
length = 6*63/length;
dir[0] *= length;
dir[1] *= length;
s = (speedscale + dir[0]) * (1.0/128);
t = (speedscale + dir[1]) * (1.0/128);
glTexCoord2f (s, t);
glVertex3fv (v);
}
glEnd ();
}
}
/*
===============
EmitBothSkyLayers
Does a sky warp on the pre-fragmented glpoly_t chain
This will be called for brushmodels, the world
will have them chained together.
===============
*/
void EmitBothSkyLayers (msurface_t *fa)
{
int i;
int lindex;
float *vec;
GL_DisableMultitexture();
GL_Bind (solidskytexture);
speedscale = realtime*8;
speedscale -= (int)speedscale & ~127 ;
EmitSkyPolys (fa);
glEnable (GL_BLEND);
GL_Bind (alphaskytexture);
speedscale = realtime*16;
speedscale -= (int)speedscale & ~127 ;
EmitSkyPolys (fa);
glDisable (GL_BLEND);
}
#ifndef QUAKE2
/*
=================
R_DrawSkyChain
=================
*/
void R_DrawSkyChain (msurface_t *s)
{
msurface_t *fa;
GL_DisableMultitexture();
// used when gl_texsort is on
GL_Bind(solidskytexture);
speedscale = realtime*8;
speedscale -= (int)speedscale & ~127 ;
for (fa=s ; fa ; fa=fa->texturechain)
EmitSkyPolys (fa);
glEnable (GL_BLEND);
GL_Bind (alphaskytexture);
speedscale = realtime*16;
speedscale -= (int)speedscale & ~127 ;
for (fa=s ; fa ; fa=fa->texturechain)
EmitSkyPolys (fa);
glDisable (GL_BLEND);
}
#endif
/*
=================================================================
Quake 2 environment sky
=================================================================
*/
/*
==================
Sky_LoadSkyBox
==================
*/
//char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
void Sky_LoadSkyBox(char* name)
{
if (strcmp(skybox_name, name) == 0)
return; //no change
//turn off skybox if sky is set to ""
if (name[0] == '0') {
skybox_name[0] = 0;
return;
}
// Do sides one way and top another, bottom is not done
for (int i = 0; i < 4; i++)
{
int mark = Hunk_LowMark ();
if(!(skyimage[i] = loadtextureimage (va("gfx/env/%s%s", name, suf[i]), 0, 0, false, false)) &&
!(skyimage[i] = loadtextureimage (va("gfx/env/%s_%s", name, suf[i]), 0, 0, false, false)))
{
Con_Printf("Sky: %s[%s] not found, used std\n", name, suf[i]);
if(!(skyimage[i] = loadtextureimage (va("gfx/env/skybox%s", suf[i]), 0, 0, false, false)))
{
Sys_Error("STD SKY NOT FOUND!");
}
}
Hunk_FreeToLowMark (mark);
}
int mark = Hunk_LowMark ();
if(!(skyimage[4] = loadtextureimage (va("gfx/env/%sup", name), 0, 0, false, false)) &&
!(skyimage[4] = loadtextureimage (va("gfx/env/%s_up", name), 0, 0, false, false)))
{
Con_Printf("Sky: %s[%s] not found, used std\n", name, suf[4]);
if(!(skyimage[4] = loadtextureimage (va("gfx/env/skybox%s", suf[4]), 0, 0, false, false)))
{
Sys_Error("STD SKY NOT FOUND!");
}
}
Hunk_FreeToLowMark (mark);
strcpy(skybox_name, name);
}
/*
=================
Sky_NewMap
=================
*/
void Sky_NewMap (void)
{
char key[128], value[4096];
char *data;
//purge old sky textures
//UnloadSkyTexture ();
//
// initially no sky
//
Sky_LoadSkyBox (""); //not used
//
// read worldspawn (this is so ugly, and shouldn't it be done on the server?)
//
data = cl.worldmodel->entities;
if (!data)
return; //FIXME: how could this possibly ever happen? -- if there's no
// worldspawn then the sever wouldn't send the loadmap message to the client
data = COM_Parse(data);
if (!data) //should never happen
return; // error
if (com_token[0] != '{') //should never happen
return; // error
while (1)
{
data = COM_Parse(data);
if (!data)
return; // error
if (com_token[0] == '}')
break; // end of worldspawn
if (com_token[0] == '_')
strcpy(key, com_token + 1);
else
strcpy(key, com_token);
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
data = COM_Parse(data);
if (!data)
return; // error
strcpy(value, com_token);
if (!strcmp("sky", key))
Sky_LoadSkyBox(value);
else if (!strcmp("skyname", key)) //half-life
Sky_LoadSkyBox(value);
else if (!strcmp("qlsky", key)) //quake lives
Sky_LoadSkyBox(value);
}
}
/*
=================
Sky_SkyCommand_f
=================
*/
void Sky_SkyCommand_f (void)
{
switch (Cmd_Argc())
{
case 1:
Con_Printf("\"sky\" is \"%s\"\n", skybox_name);
break;
case 2:
Sky_LoadSkyBox(Cmd_Argv(1));
break;
default:
Con_Printf("usage: sky <skyname>\n");
}
}
/*
=============
Sky_Init
=============
*/
void Sky_Init (void)
{
int i;
Cmd_AddCommand ("sky",Sky_SkyCommand_f);
for (i=0; i<5; i++)
skyimage[i] = NULL;
}
static vec3_t skyclip[6] = {
{1,1,0},
{1,-1,0},
{0,-1,1},
{0,1,1},
{1,0,1},
{-1,0,1}
};
int c_sky;
// 1 = s, 2 = t, 3 = 2048
static int st_to_vec[6][3] =
{
{3,-1,2},
{-3,1,2},
{1,3,2},
{-1,-3,2},
{-2,-1,3}, // 0 degrees yaw, look straight up
{2,-1,-3} // look straight down
// {-1,2,3},
// {1,2,-3}
};
// s = [0]/[2], t = [1]/[2]
static int vec_to_st[6][3] =
{
{-2,3,1},
{2,3,-1},
{1,3,2},
{-1,3,-2},
{-2,-1,3},
{-2,1,-3}
// {-1,2,3},
// {1,2,-3}
};
static float skymins[2][6], skymaxs[2][6];
/*
==============
R_ClearSkyBox
==============
*/
void R_ClearSkyBox (void)
{
int i;
for (i=0 ; i<5 ; i++)
{
skymins[0][i] = skymins[1][i] = 9999;
skymaxs[0][i] = skymaxs[1][i] = -9999;
}
}
void MakeSkyVec (float s, float t, int axis)
{
vec3_t v, b;
int j, k;
b[0] = s*2048;
b[1] = t*2048;
b[2] = 2048;
for (j=0 ; j<3 ; j++)
{
k = st_to_vec[axis][j];
if (k < 0)
v[j] = -b[-k - 1];
else
v[j] = b[k - 1];
v[j] += r_origin[j];
}
// avoid bilerp seam
s = (s+1)*0.5;
t = (t+1)*0.5;
if (s < 1.0/512)
s = 1.0/512;
else if (s > 511.0/512)
s = 511.0/512;
if (t < 1.0/512)
t = 1.0/512;
else if (t > 511.0/512)
t = 511.0/512;
t = 1.0 - t;
glTexCoord2f (s, t);
glVertex3fv (v);
}
/*
==============
R_DrawSkyBox
==============
*/
float skynormals[5][3] = {
{ 1.f, 0.f, 0.f },
{ -1.f, 0.f, 0.f },
{ 0.f, 1.f, 0.f },
{ 0.f, -1.f, 0.f },
{ 0.f, 0.f, 1.f }
};
float skyrt[5][3] = {
{ 0.f, -1.f, 0.f },
{ 0.f, 1.f, 0.f },
{ 1.f, 0.f, 0.f },
{ -1.f, 0.f, 0.f },
{ 0.f, -1.f, 0.f }
};
float skyup[5][3] = {
{ 0.f, 0.f, 1.f },
{ 0.f, 0.f, 1.f },
{ 0.f, 0.f, 1.f },
{ 0.f, 0.f, 1.f },
{ -1.f, 0.f, 0.f }
};
void R_DrawSkyBox (void)
{
int i, j, k;
vec3_t v;
float s, t;
//Fog_DisableGFog();
//Fog_SetColorForSkyS();
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
float skydepth = 1000.0f;
for (i=0 ; i<5 ; i++)
{
const int vertex_count = 4;
glvert_t sky_vertices[vertex_count];
// check if poly needs to be drawn at all
float dot = DotProduct(skynormals[i], vpn);
// < 0 check would work at fov 90 or less, just guess a value that's high enough?
if (dot < -0.25f) continue;
GL_Bind(skyimage[skytexorder[i]]);
// if direction is not up, cut "down" vector to zero to only render half cube
//float upnegfact = i == 4 ? 1.0f : 0.0f;
float upnegfact = 1.0f;
float skyboxtexsize = 256.f;
// move ever so slightly less towards forward to make edges overlap a bit, just to not have shimmering pixels between sky edges
float forwardfact = 0.99f;
glBegin(GL_QUADS);
sky_vertices[0].s = 0.5f / skyboxtexsize;
sky_vertices[0].t = (skyboxtexsize - .5f) / skyboxtexsize;
sky_vertices[0].x = r_origin[0] + (forwardfact * skynormals[i][0] - skyrt[i][0] - skyup[i][0] * upnegfact) * skydepth;
sky_vertices[0].y = r_origin[1] + (forwardfact * skynormals[i][1] - skyrt[i][1] - skyup[i][1] * upnegfact) * skydepth;
sky_vertices[0].z = r_origin[2] + (forwardfact * skynormals[i][2] - skyrt[i][2] - skyup[i][2] * upnegfact) * skydepth;
v[0] = sky_vertices[0].x;
v[1] = sky_vertices[0].y;
v[2] = sky_vertices[0].z;
glTexCoord2f (sky_vertices[0].s, sky_vertices[0].t);
glVertex3fv (v);
sky_vertices[1].s = 0.5f / skyboxtexsize;
sky_vertices[1].t = 0.5f / skyboxtexsize;
sky_vertices[1].x = r_origin[0] + (forwardfact * skynormals[i][0] - skyrt[i][0] + skyup[i][0]) * skydepth;
sky_vertices[1].y = r_origin[1] + (forwardfact * skynormals[i][1] - skyrt[i][1] + skyup[i][1]) * skydepth;
sky_vertices[1].z = r_origin[2] + (forwardfact * skynormals[i][2] - skyrt[i][2] + skyup[i][2]) * skydepth;
v[0] = sky_vertices[1].x;
v[1] = sky_vertices[1].y;
v[2] = sky_vertices[1].z;
glTexCoord2f (sky_vertices[1].s, sky_vertices[1].t);
glVertex3fv (v);
sky_vertices[2].s = (skyboxtexsize - .5f) / skyboxtexsize;
sky_vertices[2].t = 0.5f / skyboxtexsize;
sky_vertices[2].x = r_origin[0] + (forwardfact * skynormals[i][0] + skyrt[i][0] + skyup[i][0]) * skydepth;
sky_vertices[2].y = r_origin[1] + (forwardfact * skynormals[i][1] + skyrt[i][1] + skyup[i][1]) * skydepth;
sky_vertices[2].z = r_origin[2] + (forwardfact * skynormals[i][2] + skyrt[i][2] + skyup[i][2]) * skydepth;
v[0] = sky_vertices[2].x;
v[1] = sky_vertices[2].y;
v[2] = sky_vertices[2].z;
glTexCoord2f (sky_vertices[2].s, sky_vertices[2].t);
glVertex3fv (v);
sky_vertices[3].s = (skyboxtexsize - .5f) / skyboxtexsize;
sky_vertices[3].t = (skyboxtexsize - .5f) / skyboxtexsize;
sky_vertices[3].x = r_origin[0] + (forwardfact * skynormals[i][0] + skyrt[i][0] - skyup[i][0] * upnegfact) * skydepth;
sky_vertices[3].y = r_origin[1] + (forwardfact * skynormals[i][1] + skyrt[i][1] - skyup[i][1] * upnegfact) * skydepth;
sky_vertices[3].z = r_origin[2] + (forwardfact * skynormals[i][2] + skyrt[i][2] - skyup[i][2] * upnegfact) * skydepth;
v[0] = sky_vertices[3].x;
v[1] = sky_vertices[3].y;
v[2] = sky_vertices[3].z;
glTexCoord2f (sky_vertices[3].s, sky_vertices[3].t);
glVertex3fv (v);
glEnd();
}
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
//Fog_SetColorForSkyE(); //setup for Sky
//Fog_EnableGFog(); //setup for Sky
}
//===============================================================
/*
=============
R_InitSky
A sky texture is 256*128, with the right side being a masked overlay
==============
*/
void R_InitSky (miptex_t *mt)
{
int i, j, p;
byte *src;
unsigned trans[128*128];
unsigned transpix;
int r, g, b;
unsigned *rgba;
extern int skytexturenum;
src = (byte *)mt + mt->offsets[0];
// make an average value for the back to avoid
// a fringe on the top level
r = g = b = 0;
for (i=0 ; i<128 ; i++)
for (j=0 ; j<128 ; j++)
{
p = src[i*256 + j + 128];
rgba = &d_8to24table[p];
trans[(i*128) + j] = *rgba;
r += ((byte *)rgba)[0];
g += ((byte *)rgba)[1];
b += ((byte *)rgba)[2];
}
((byte *)&transpix)[0] = r/(128*128);
((byte *)&transpix)[1] = g/(128*128);
((byte *)&transpix)[2] = b/(128*128);
((byte *)&transpix)[3] = 0;
if (!solidskytexture)
solidskytexture = texture_extension_number++;
GL_Bind (solidskytexture );
glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
for (i=0 ; i<128 ; i++)
for (j=0 ; j<128 ; j++)
{
p = src[i*256 + j];
if (p == 0)
trans[(i*128) + j] = transpix;
else
trans[(i*128) + j] = d_8to24table[p];
}
if (!alphaskytexture)
alphaskytexture = texture_extension_number++;
GL_Bind(alphaskytexture);
glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

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.
*/
0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677,
1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916,
3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998,
4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632,
5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068,
6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368,
7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562,
7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759,
8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222,
7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394,
7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883,
6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398,
5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647,
4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193,
3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281,
1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633,
9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677,
-1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916,
-3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998,
-4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632,
-5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068,
-6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368,
-7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562,
-7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759,
-8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222,
-7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394,
-7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883,
-6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398,
-5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647,
-4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193,
-3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281,
-1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633,

368
source/ctr/glquake.h Normal file
View file

@ -0,0 +1,368 @@
/*
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 _WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
#include <GL/glu.h>
void GL_BeginRendering (int *x, int *y, int *width, int *height);
void GL_EndRendering (void);
#ifdef _WIN32
// Function prototypes for the Texture Object Extension routines
typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,
const GLboolean *);
typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint);
typedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *);
typedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *);
typedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint);
typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *,
const GLclampf *);
typedef void (APIENTRY *TEXSUBIMAGEPTR)(int, int, int, int, int, int, int, int, void *);
extern BINDTEXFUNCPTR bindTexFunc;
extern DELTEXFUNCPTR delTexFunc;
extern TEXSUBIMAGEPTR TexSubImage2DFunc;
#endif
extern int texture_extension_number;
extern int texture_mode;
extern float gldepthmin, gldepthmax;
void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha);
void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha);
int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel);
int GL_FindTexture (char *identifier);
typedef struct
{
float x, y, z;
float s, t;
float r, g, b;
} glvert_t;
extern glvert_t glv;
extern int glx, gly, glwidth, glheight;
#ifdef _WIN32
extern PROC glArrayElementEXT;
extern PROC glColorPointerEXT;
extern PROC glTexturePointerEXT;
extern PROC glVertexPointerEXT;
#endif
/*
---------------------------------
half-life Render Modes. Crow_bar
---------------------------------
*/
#define TEX_COLOR 1
#define TEX_TEXTURE 2
#define TEX_GLOW 3
#define TEX_SOLID 4
#define TEX_ADDITIVE 5
#define TEX_LMPOINT 6 //for light point
#define ISCOLOR(ent) ((ent)->rendermode == TEX_COLOR && ((ent)->rendercolor[0] <= 1|| \
(ent)->rendercolor[1] <= 1|| \
(ent)->rendercolor[2] <= 1))
#define ISTEXTURE(ent) ((ent)->rendermode == TEX_TEXTURE && (ent)->renderamt > 0 && (ent)->renderamt <= 1)
#define ISGLOW(ent) ((ent)->rendermode == TEX_GLOW && (ent)->renderamt > 0 && (ent)->renderamt <= 1)
#define ISSOLID(ent) ((ent)->rendermode == TEX_SOLID && (ent)->renderamt > 0 && (ent)->renderamt <= 1)
#define ISADDITIVE(ent) ((ent)->rendermode == TEX_ADDITIVE && (ent)->renderamt > 0 && (ent)->renderamt <= 1)
#define ISLMPOINT(ent) ((ent)->rendermode == TEX_LMPOINT && ((ent)->rendercolor[0] <= 1|| \
(ent)->rendercolor[1] <= 1|| \
(ent)->rendercolor[2] <= 1))
/*
---------------------------------
//half-life Render Modes
---------------------------------
*/
// r_local.h -- private refresh defs
#define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0)
// normalizing factor so player model works out to about
// 1 pixel per triangle
#define MAX_LBM_HEIGHT 480
#define TILE_SIZE 128 // size of textures generated by R_GenTiledSurf
#define SKYSHIFT 7
#define SKYSIZE (1 << SKYSHIFT)
#define SKYMASK (SKYSIZE - 1)
#define BACKFACE_EPSILON 0.01
void R_TimeRefresh_f (void);
void R_ReadPointFile_f (void);
texture_t *R_TextureAnimation (texture_t *base);
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
byte data[4]; // width*height elements
} surfcache_t;
typedef enum
{
pm_classic, pm_qmb, pm_quake3, pm_mixed
} part_mode_t;
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;
typedef enum {
pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2
} ptype_t;
typedef byte col_t[4];
typedef struct particle_s
{
struct particle_s *next;
vec3_t org, endorg;
col_t color;
float growth;
vec3_t vel;
float ramp;
ptype_t type;
float rotangle;
float rotspeed;
float size;
float start;
float die;
byte hit;
byte texindex;
byte bounces;
} particle_t;
//====================================================
extern entity_t r_worldentity;
extern qboolean r_cache_thrash; // compatability
extern vec3_t modelorg, r_entorigin;
extern entity_t *currententity;
extern int r_visframecount; // ??? what difs?
extern int r_framecount;
extern mplane_t frustum[4];
extern int c_brush_polys, c_alias_polys;
//
// view origin
//
extern vec3_t vup;
extern vec3_t vpn;
extern vec3_t vright;
extern vec3_t r_origin;
//
// screen size info
//
extern refdef_t r_refdef;
extern mleaf_t *r_viewleaf, *r_oldviewleaf;
extern texture_t *r_notexture_mip;
extern int d_lightstylevalue[256]; // 8.8 fraction of base light value
extern qboolean envmap;
extern int currenttexture;
extern int cnttextures[2];
extern int particletexture;
extern int playertextures;
extern int skytexturenum; // index in cl.loadmodel, not gl texture object
extern cvar_t r_norefresh;
extern cvar_t r_drawentities;
extern cvar_t r_drawworld;
extern cvar_t r_drawviewmodel;
extern cvar_t r_speeds;
extern cvar_t r_waterwarp;
extern cvar_t r_fullbright;
extern cvar_t r_lightmap;
extern cvar_t r_shadows;
extern cvar_t r_mirroralpha;
extern cvar_t r_wateralpha;
extern cvar_t r_dynamic;
extern cvar_t r_novis;
extern cvar_t r_farclip;
extern cvar_t r_skyfog;
extern cvar_t r_laserpoint;
extern cvar_t r_particle_count;
extern cvar_t r_part_explosions;
extern cvar_t r_part_trails;
extern cvar_t r_part_sparks;
extern cvar_t r_part_spikes;
extern cvar_t r_part_gunshots;
extern cvar_t r_part_blood;
extern cvar_t r_part_telesplash;
extern cvar_t r_part_blobs;
extern cvar_t r_part_lavasplash;
extern cvar_t r_part_flames;
extern cvar_t r_part_lightning;
extern cvar_t r_part_flies;
extern cvar_t r_bounceparticles;
extern cvar_t r_explosiontype;
extern cvar_t r_part_muzzleflash;
extern cvar_t r_flametype;
extern cvar_t r_bounceparticles;
extern cvar_t r_decal_blood;
extern cvar_t r_decal_bullets;
extern cvar_t r_decal_sparks;
extern cvar_t r_decal_explosions;
extern cvar_t r_coronas;
extern cvar_t r_model_brightness;
extern cvar_t gl_clear;
extern cvar_t gl_cull;
extern cvar_t gl_poly;
extern cvar_t gl_texsort;
extern cvar_t gl_smoothmodels;
extern cvar_t gl_affinemodels;
extern cvar_t gl_polyblend;
extern cvar_t gl_keeptjunctions;
extern cvar_t gl_reporttjunctions;
extern cvar_t gl_flashblend;
extern cvar_t gl_nocolors;
extern cvar_t gl_doubleeyes;
extern int gl_lightmap_format;
extern int gl_solid_format;
extern int gl_alpha_format;
extern cvar_t gl_max_size;
extern cvar_t gl_playermip;
extern int mirrortexturenum; // quake texturenum, not gltexturenum
extern qboolean mirror;
extern mplane_t *mirror_plane;
extern float r_world_matrix[16];
extern const char *gl_vendor;
extern const char *gl_renderer;
extern const char *gl_version;
extern const char *gl_extensions;
void R_TranslatePlayerSkin (int playernum);
void GL_Bind (int texnum);
// Multitexture
#define TEXTURE0_SGIS 0x835E
#define TEXTURE1_SGIS 0x835F
#ifndef _WIN32
#define APIENTRY /* */
#endif
typedef void (APIENTRY *lpMTexFUNC) (GLenum, GLfloat, GLfloat);
typedef void (APIENTRY *lpSelTexFUNC) (GLenum);
extern lpMTexFUNC qglMTexCoord2fSGIS;
extern lpSelTexFUNC qglSelectTextureSGIS;
extern qboolean gl_mtexable;
void GL_DisableMultitexture(void);
void GL_EnableMultitexture(void);
//johnfitz -- fog functions called from outside gl_fog.c
void Fog_ParseServerMessage (void);
float *Fog_GetColor (void);
float Fog_GetDensity (void);
void Fog_EnableGFog (void);
void Fog_DisableGFog (void);
void Fog_StartAdditive (void);
void Fog_StopAdditive (void);
void Fog_SetupFrame (void);
void Fog_NewMap (void);
void Fog_Init (void);
void Fog_SetupState (void);
void Sky_Init (void);
void Sky_NewMap (void);
qboolean VID_Is8bit(void);
// naievil -- fixme: none of these work
//-----------------------------------------------------
void QMB_InitParticles (void);
void QMB_ClearParticles (void);
void QMB_DrawParticles (void);
void QMB_Q3TorchFlame (vec3_t org, float size);
void QMB_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);
void QMB_RocketTrail (vec3_t start, vec3_t end, trail_type_t type);
void QMB_BlobExplosion (vec3_t org);
void QMB_ParticleExplosion (vec3_t org);
void QMB_LavaSplash (vec3_t org);
void QMB_TeleportSplash (vec3_t org);
void QMB_InfernoFlame (vec3_t org);
void QMB_StaticBubble (entity_t *ent);
void QMB_ColorMappedExplosion (vec3_t org, int colorStart, int colorLength);
void QMB_TorchFlame (vec3_t org);
void QMB_FlameGt (vec3_t org, float size, float time);
void QMB_BigTorchFlame (vec3_t org);
void QMB_ShamblerCharge (vec3_t org);
void QMB_LightningBeam (vec3_t start, vec3_t end);
//void QMB_GenSparks (vec3_t org, byte col[3], float count, float size, float life);
void QMB_EntityParticles (entity_t *ent);
void QMB_MuzzleFlash (vec3_t org);
void QMB_RayFlash (vec3_t org, float weapon);
void QMB_MuzzleFlashLG (vec3_t org);
void QMB_Q3Gunshot (vec3_t org, int skinnum, float alpha);
void QMB_Q3Teleport (vec3_t org, float alpha);
void QMB_Q3TorchFlame (vec3_t org, float size);
extern qboolean qmb_initialized;

240
source/ctr/in_ctr.c Normal file
View file

@ -0,0 +1,240 @@
/*
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.
*/
// in_ctr.c -- for the Nintendo 3DS
#include "../quakedef.h"
#include <GL/picaGL.h>
#include <3ds.h>
extern int bind_grab;
extern bool new3ds_flag;
extern bool croshhairmoving;
extern float crosshair_opacity;
extern cvar_t in_analog_strafe;
extern cvar_t in_x_axis_adjust;
extern cvar_t in_y_axis_adjust;
extern cvar_t in_mlook; //Heffo - mlook cvar
cvar_t in_anub_mode = {"in_anub_mode", "0", true};
void IN_Init (void)
{
Cvar_RegisterVariable (&in_analog_strafe);
Cvar_RegisterVariable (&in_anub_mode);
if (new3ds_flag) {
Cvar_SetValue("in_anub_mode", 1);
}
}
void IN_Shutdown (void)
{
}
void IN_Commands (void)
{
}
float IN_CalcInput(int axis, float speed, float tolerance, float acceleration) {
float value = ((float) axis / 154.0f);
if (value == 0.0f) {
return 0.0f;
}
float abs_value = fabs(value);
if (abs_value < tolerance) {
return 0.0f;
}
abs_value -= tolerance;
abs_value /= (1.0f - tolerance);
abs_value = powf(abs_value, acceleration);
abs_value *= speed;
if (value < 0.0f) {
value = -abs_value;
} else {
value = abs_value;
}
return value;
}
extern cvar_t scr_fov;
extern int original_fov, final_fov;
touchPosition old_touch, cur_touch;
void IN_Move (usercmd_t *cmd)
{
// Touch based viewangles based on Quake2CTR
// This was originally based on ctrQuake, however
// that implementation was less elegant and had
// a weird jerk bug when tapping the screen.
if(hidKeysDown() & KEY_TOUCH)
hidTouchRead(&old_touch);
if((hidKeysHeld() & KEY_TOUCH))
{
hidTouchRead(&cur_touch);
if(cur_touch.px < 268)
{
int tx = cur_touch.px - old_touch.px;
int ty = cur_touch.py - old_touch.py;
if(m_pitch.value < 0)
ty = -ty;
cl.viewangles[YAW] -= abs(tx) > 1 ? tx * sensitivity.value * 0.33f : 0;
cl.viewangles[PITCH] += abs(ty) > 1 ? ty * sensitivity.value * 0.33f : 0;
}
old_touch = cur_touch;
}
// TODO: Detect circle pad pro?
circlePosition left;
circlePosition right;
V_StopPitchDrift();
// Read the pad states
hidCircleRead(&left);
hidCstickRead(&right);
// Convert the inputs to floats in the range [-1, 1].
// Implement the dead zone.
float speed;
float deadZone = in_tolerance.value;
float acceleration = in_acceleration.value;
float look_x, look_y;
//
// Analog look tweaks
//
speed = sensitivity.value;
if (!in_anub_mode.value)
speed -= 2;
else
speed += 8;
// cut look speed in half when facing enemy, unless mag is empty
if ((in_aimassist.value) && (sv_player->v.facingenemy == 1) && cl.stats[STAT_CURRENTMAG] > 0) {
speed *= 0.5;
}
// additionally, slice look speed when ADS/scopes
if (cl.stats[STAT_ZOOM] == 1)
speed *= 0.5;
else if (cl.stats[STAT_ZOOM] == 2)
speed *= 0.25;
// Are we using the left or right stick for looking?
if (!in_anub_mode.value) { // Left
look_x = IN_CalcInput(left.dx, speed, deadZone, acceleration);
look_y = IN_CalcInput(left.dy, speed, deadZone, acceleration);
} else { // Right
look_x = IN_CalcInput(right.dx, speed, deadZone, acceleration);
look_y = IN_CalcInput(right.dy, speed, deadZone, acceleration);
}
const float yawScale = 30.0f;
cl.viewangles[YAW] -= yawScale * look_x * host_frametime;
// Set the pitch.
const bool invertPitch = m_pitch.value < 0;
const float pitchScale = yawScale * (invertPitch ? 1 : -1);
cl.viewangles[PITCH] += pitchScale * look_y * host_frametime;
// Don't look too far up or down.
if (cl.viewangles[PITCH] > 80.0f)
cl.viewangles[PITCH] = 80.0f;
if (cl.viewangles[PITCH] < -70.0f)
cl.viewangles[PITCH] = -70.0f;
// Ability to move with the left nub on NEW model systems
float move_x, move_y;
float input_x, input_y;
if (in_anub_mode.value) {
input_x = left.dx;
input_y = left.dy;
} else {
input_x = right.dx;
input_y = right.dy;
}
cl_backspeed = cl_forwardspeed = cl_sidespeed = sv_player->v.maxspeed;
cl_sidespeed *= 0.8;
cl_backspeed *= 0.7;
move_x = IN_CalcInput(input_x, cl_sidespeed, deadZone, acceleration);
if (input_y > 0)
move_y = IN_CalcInput(input_y, cl_forwardspeed, deadZone, acceleration);
else
move_y = IN_CalcInput(input_y, cl_backspeed, deadZone, acceleration);
// cypress -- explicitly setting instead of adding so we always prioritize
// analog movement over standard bindings if both are at play
if (move_x != 0 || move_y != 0) {
cmd->sidemove = move_x;
cmd->forwardmove = move_y;
}
// crosshair stuff
if (input_x < 50 && input_x > -50 && input_y < 50 && input_y > -50) {
croshhairmoving = false;
crosshair_opacity += 22;
if (crosshair_opacity >= 255)
crosshair_opacity = 255;
} else {
croshhairmoving = true;
crosshair_opacity -= 8;
if (crosshair_opacity <= 128)
crosshair_opacity = 128;
}
}
//
// ctr software keyboard courtesy of libctru samples
//
void IN_SwitchKeyboard(void)
{
static SwkbdState swkbd;
static char console_buffer[64];
SwkbdButton button = SWKBD_BUTTON_NONE;
swkbdInit(&swkbd, SWKBD_TYPE_QWERTY, 2, -1);
swkbdSetInitialText(&swkbd, console_buffer);
swkbdSetHintText(&swkbd, "Enter Quake console command");
swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Send", true);
button = swkbdInputText(&swkbd, console_buffer, sizeof(console_buffer));
Cbuf_AddText(va("%s\n", console_buffer));
}

947
source/ctr/keys.c Normal file
View file

@ -0,0 +1,947 @@
/*
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.
*/
#include "../quakedef.h"
/*
key up events are sent even if in console mode
*/
#define MAXCMDLINE 256
char key_lines[32][MAXCMDLINE];
int key_linepos;
int shift_down=false;
int key_lastpress;
int edit_line=0;
int history_line=0;
keydest_t key_dest;
int key_count; // incremented every key event
char *keybindings[256];
char *dtbindings[256];
qboolean consolekeys[256]; // if true, can't be rebound while in console
qboolean menubound[256]; // if true, can't be rebound while in menu
int keyshift[256]; // key to map to if shift held down in console
int key_repeats[256]; // if > 1, it is autorepeating
qboolean keydown[256];
typedef struct
{
char *name;
int keynum;
} keyname_t;
keyname_t keynames[] =
{
#ifdef _3DS
{"TAB", K_TAB},
{"START", K_ESCAPE},
{"SELECT", K_SELECT},
{"SPACE", K_SPACE},
{"BACKSPACE", K_BACKSPACE},
{"PADUP", K_UPARROW},
{"PADDOWN", K_DOWNARROW},
{"PADLEFT", K_LEFTARROW},
{"PADRIGHT", K_RIGHTARROW},
#else
{"TAB", K_TAB},
{"ENTER", K_ENTER},
{"ESCAPE", K_ESCAPE},
{"SPACE", K_SPACE},
{"BACKSPACE", K_BACKSPACE},
{"UPARROW", K_UPARROW},
{"DOWNARROW", K_DOWNARROW},
{"LEFTARROW", K_LEFTARROW},
{"RIGHTARROW", K_RIGHTARROW},
#endif
{"ALT", K_ALT},
{"CTRL", K_CTRL},
{"SHIFT", K_SHIFT},
{"F1", K_F1},
{"F2", K_F2},
{"F3", K_F3},
{"F4", K_F4},
{"F5", K_F5},
{"F6", K_F6},
{"F7", K_F7},
{"F8", K_F8},
{"F9", K_F9},
{"F10", K_F10},
{"F11", K_F11},
{"F12", K_F12},
{"INS", K_INS},
{"DEL", K_DEL},
{"PGDN", K_PGDN},
{"PGUP", K_PGUP},
{"HOME", K_HOME},
{"END", K_END},
{"MOUSE1", K_MOUSE1},
{"MOUSE2", K_MOUSE2},
{"MOUSE3", K_MOUSE3},
{"JOY1", K_JOY1},
{"JOY2", K_JOY2},
{"JOY3", K_JOY3},
{"JOY4", K_JOY4},
#ifdef _3DS
{"ABUTTON", K_AUX1},
{"BBUTTON", K_AUX2},
{"XBUTTON", K_AUX3},
{"YBUTTON", K_AUX4},
{"LTRIGGER", K_AUX5},
{"ZLTRIGGER", K_AUX6},
{"RTRIGGER", K_AUX7},
{"ZRTRIGGER", K_AUX8},
{"T1", K_AUX9},
{"T2", K_AUX10},
{"T3", K_AUX11},
{"T4", K_AUX12},
{"T5", K_AUX13},
{"T6", K_AUX14},
{"AUX15", K_AUX15},
{"AUX16", K_AUX16},
{"AUX17", K_AUX17},
{"AUX18", K_AUX18},
{"AUX19", K_AUX19},
{"AUX20", K_AUX20},
{"AUX21", K_AUX21},
{"AUX22", K_AUX22},
{"AUX23", K_AUX23},
{"AUX24", K_AUX24},
{"AUX25", K_AUX25},
{"AUX26", K_AUX26},
{"AUX27", K_AUX27},
{"AUX28", K_AUX28},
{"AUX29", K_AUX29},
{"AUX30", K_AUX30},
{"AUX31", K_AUX31},
{"AUX32", K_AUX32},
#else
{"AUX1", K_AUX1},
{"AUX2", K_AUX2},
{"AUX3", K_AUX3},
{"AUX4", K_AUX4},
{"AUX5", K_AUX5},
{"AUX6", K_AUX6},
{"AUX7", K_AUX7},
{"AUX8", K_AUX8},
{"AUX9", K_AUX9},
{"AUX10", K_AUX10},
{"AUX11", K_AUX11},
{"AUX12", K_AUX12},
{"AUX13", K_AUX13},
{"AUX14", K_AUX14},
{"AUX15", K_AUX15},
{"AUX16", K_AUX16},
{"AUX17", K_AUX17},
{"AUX18", K_AUX18},
{"AUX19", K_AUX19},
{"AUX20", K_AUX20},
{"AUX21", K_AUX21},
{"AUX22", K_AUX22},
{"AUX23", K_AUX23},
{"AUX24", K_AUX24},
{"AUX25", K_AUX25},
{"AUX26", K_AUX26},
{"AUX27", K_AUX27},
{"AUX28", K_AUX28},
{"AUX29", K_AUX29},
{"AUX30", K_AUX30},
{"AUX31", K_AUX31},
{"AUX32", K_AUX32},
#endif
{"PAUSE", K_PAUSE},
{"MWHEELUP", K_MWHEELUP},
{"MWHEELDOWN", K_MWHEELDOWN},
{"SEMICOLON", ';'}, // because a raw semicolon seperates commands
{NULL,0}
};
/*
==============================================================================
LINE TYPING INTO THE CONSOLE
==============================================================================
*/
/*
====================
Key_Console
Interactive line editing and console scrollback
====================
*/
extern qboolean console_enabled;
void Key_Console (int key)
{
char *cmd;
if (key == K_SELECT)
{
IN_SwitchKeyboard();
return;
}
if (key == K_JOY3 || key == K_ENTER)
{
Cbuf_AddText (key_lines[edit_line]+1); // skip the >
Cbuf_AddText ("\n");
Con_Printf ("%s\n",key_lines[edit_line]);
edit_line = (edit_line + 1) & 31;
history_line = edit_line;
key_lines[edit_line][0] = ']';
key_linepos = 1;
if (cls.state == ca_disconnected)
SCR_UpdateScreen (); // force an update, because the command
// may take some time
// for clientside cmds
if (cls.state == ca_connected){
pr_global_struct->CMD_STRING = (key_lines[edit_line-1]+1 - pr_strings);
PR_ExecuteProgram (pr_global_struct->ParseClientCommand);
}
return;
}
if (key == K_TAB)
{ // command completion
cmd = Cmd_CompleteCommand (key_lines[edit_line]+1);
if (!cmd)
cmd = Cvar_CompleteVariable (key_lines[edit_line]+1);
if (cmd)
{
Q_strcpy (key_lines[edit_line]+1, cmd);
key_linepos = Q_strlen(cmd)+1;
key_lines[edit_line][key_linepos] = ' ';
key_linepos++;
key_lines[edit_line][key_linepos] = 0;
return;
}
}
if (key == K_BACKSPACE || key == K_LEFTARROW)
{
if (key_linepos > 1)
key_linepos--;
return;
}
if (key == K_UPARROW)
{
do
{
history_line = (history_line - 1) & 31;
} while (history_line != edit_line
&& !key_lines[history_line][1]);
if (history_line == edit_line)
history_line = (edit_line+1)&31;
Q_strcpy(key_lines[edit_line], key_lines[history_line]);
key_linepos = Q_strlen(key_lines[edit_line]);
return;
}
if (key == K_DOWNARROW)
{
if (history_line == edit_line) return;
do
{
history_line = (history_line + 1) & 31;
}
while (history_line != edit_line
&& !key_lines[history_line][1]);
if (history_line == edit_line)
{
key_lines[edit_line][0] = ']';
key_linepos = 1;
}
else
{
Q_strcpy(key_lines[edit_line], key_lines[history_line]);
key_linepos = Q_strlen(key_lines[edit_line]);
}
return;
}
if (key == K_PGUP || key==K_MWHEELUP)
{
con_backscroll += 2;
if (con_backscroll > con_totallines - (vid.height>>3) - 1)
con_backscroll = con_totallines - (vid.height>>3) - 1;
return;
}
if (key == K_PGDN || key==K_MWHEELDOWN)
{
con_backscroll -= 2;
if (con_backscroll < 0)
con_backscroll = 0;
return;
}
if (key == K_HOME)
{
con_backscroll = con_totallines - (vid.height>>3) - 1;
return;
}
if (key == K_END)
{
console_enabled = false;
con_backscroll = 0;
return;
}
if (key < 32 || key > 127)
return; // non printable
if (key_linepos < MAXCMDLINE-1)
{
key_lines[edit_line][key_linepos] = key;
key_linepos++;
key_lines[edit_line][key_linepos] = 0;
}
}
//============================================================================
char chat_buffer[32];
qboolean team_message = false;
void Key_Message (int key)
{
static int chat_bufferlen = 0;
if (key == K_ENTER)
{
if (team_message)
Cbuf_AddText ("say_team \"");
else
Cbuf_AddText ("say \"");
Cbuf_AddText(chat_buffer);
Cbuf_AddText("\"\n");
key_dest = key_game;
chat_bufferlen = 0;
chat_buffer[0] = 0;
return;
}
if (key == K_ESCAPE)
{
console_enabled = false;
key_dest = key_game;
chat_bufferlen = 0;
chat_buffer[0] = 0;
return;
}
if (key < 32 || key > 127)
return; // non printable
if (key == K_BACKSPACE)
{
if (chat_bufferlen)
{
chat_bufferlen--;
chat_buffer[chat_bufferlen] = 0;
}
return;
}
if (chat_bufferlen == 31)
return; // all full
chat_buffer[chat_bufferlen++] = key;
chat_buffer[chat_bufferlen] = 0;
}
//============================================================================
/*
===================
Key_StringToKeynum
Returns a key number to be used to index keybindings[] by looking at
the given string. Single ascii characters return themselves, while
the K_* names are matched up.
===================
*/
int Key_StringToKeynum (char *str)
{
keyname_t *kn;
if (!str || !str[0])
return -1;
if (!str[1])
return str[0];
for (kn=keynames ; kn->name ; kn++)
{
if (!Q_strcasecmp(str,kn->name))
return kn->keynum;
}
return -1;
}
/*
===================
Key_KeynumToString
Returns a string (either a single ascii char, or a K_* name) for the
given keynum.
FIXME: handle quote special (general escape sequence?)
===================
*/
char *Key_KeynumToString (int keynum)
{
keyname_t *kn;
static char tinystr[2];
if (keynum == -1)
return "<KEY NOT FOUND>";
if (keynum > 32 && keynum < 127)
{ // printable ascii
tinystr[0] = keynum;
tinystr[1] = 0;
return tinystr;
}
for (kn=keynames ; kn->name ; kn++)
if (keynum == kn->keynum)
return kn->name;
return "<UNKNOWN KEYNUM>";
}
/*
===================
Key_SetBinding
===================
*/
void Key_SetBinding (int keynum, char *binding)
{
char *new;
int l;
if (keynum == -1)
return;
// free old bindings
if (keybindings[keynum])
{
Z_Free (keybindings[keynum]);
keybindings[keynum] = NULL;
}
// allocate memory for new binding
l = Q_strlen (binding);
new = Z_Malloc (l+1);
Q_strcpy (new, binding);
new[l] = 0;
keybindings[keynum] = new;
}
/*
===================
Key_SetDTBinding
===================
*/
void Key_SetDTBinding (int keynum, char *binding)
{
char *new;
int l;
if (keynum == -1)
return;
// free old bindings
if (dtbindings[keynum])
{
Z_Free (dtbindings[keynum]);
dtbindings[keynum] = NULL;
}
// allocate memory for new binding
l = Q_strlen (binding);
new = Z_Malloc (l+1);
Q_strcpy (new, binding);
new[l] = 0;
dtbindings[keynum] = new;
}
/*
===================
Key_Unbind_f
===================
*/
void Key_Unbind_f (void)
{
int b;
if (Cmd_Argc() != 2)
{
Con_Printf ("unbind <key> : remove commands from a key\n");
return;
}
b = Key_StringToKeynum (Cmd_Argv(1));
if (b==-1)
{
Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
return;
}
Key_SetBinding (b, "");
}
void Key_Unbindall_f (void)
{
int i;
for (i=0 ; i<256 ; i++)
if (keybindings[i])
Key_SetBinding (i, "");
}
/*
===================
Key_Bind_f
===================
*/
void Key_Bind_f (void)
{
int i, c, b;
char cmd[1024];
c = Cmd_Argc();
if (c != 2 && c != 3)
{
Con_Printf ("bind <key> [command] : attach a command to a key\n");
return;
}
b = Key_StringToKeynum (Cmd_Argv(1));
if (b==-1)
{
Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
return;
}
if (c == 2)
{
if (keybindings[b])
Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
else
Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
return;
}
// copy the rest of the command line
cmd[0] = 0; // start out with a null string
for (i=2 ; i< c ; i++)
{
if (i > 2)
strcat (cmd, " ");
strcat (cmd, Cmd_Argv(i));
}
Key_SetBinding (b, cmd);
}
/*
===================
Key_Binddt_f
===================
*/
void Key_Binddt_f (void)
{
int i, c, b;
char cmd[1024];
c = Cmd_Argc();
if (c != 2 && c != 3)
{
Con_Printf ("binddt <key> [command] : attach a command to a double tap key\n");
return;
}
b = Key_StringToKeynum (Cmd_Argv(1));
if (b==-1)
{
Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
return;
}
if (c == 2)
{
if (dtbindings[b])
Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), dtbindings[b] );
else
Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
return;
}
// copy the rest of the command line
cmd[0] = 0; // start out with a null string
for (i=2 ; i< c ; i++)
{
if (i > 2)
strcat (cmd, " ");
strcat (cmd, Cmd_Argv(i));
}
Key_SetDTBinding (b, cmd);
}
/*
============
Key_WriteBindings
Writes lines containing "bind key value"
============
*/
void Key_WriteBindings (FILE *f)
{
int i;
for (i=0 ; i<256 ; i++)
if (keybindings[i])
if (*keybindings[i])
fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
}
/*
============
Key_WriteDTBindings
Writes lines containing "binddt key value"
============
*/
void Key_WriteDTBindings (FILE *f)
{
int i;
for (i=0 ; i<256 ; i++)
if (dtbindings[i])
if (*dtbindings[i])
fprintf (f, "binddt \"%s\" \"%s\"\n", Key_KeynumToString(i), dtbindings[i]);
}
/*
===================
Key_Init
===================
*/
void Key_Init (void)
{
int i;
for (i=0 ; i<32 ; i++)
{
key_lines[i][0] = ']';
key_lines[i][1] = 0;
}
key_linepos = 1;
//
// init ascii characters in console mode
//
for (i=32 ; i<128 ; i++)
consolekeys[i] = true;
consolekeys[K_ENTER] = true;
consolekeys[K_TAB] = true;
consolekeys[K_LEFTARROW] = true;
consolekeys[K_RIGHTARROW] = true;
consolekeys[K_UPARROW] = true;
consolekeys[K_DOWNARROW] = true;
consolekeys[K_BACKSPACE] = true;
consolekeys[K_PGUP] = true;
consolekeys[K_PGDN] = true;
consolekeys[K_SHIFT] = true;
consolekeys[K_MWHEELUP] = true;
consolekeys[K_MWHEELDOWN] = true;
consolekeys[K_SELECT] = true;
consolekeys['`'] = false;
consolekeys['~'] = false;
for (i=0 ; i<256 ; i++)
keyshift[i] = i;
for (i='a' ; i<='z' ; i++)
keyshift[i] = i - 'a' + 'A';
keyshift['1'] = '!';
keyshift['2'] = '@';
keyshift['3'] = '#';
keyshift['4'] = '$';
keyshift['5'] = '%';
keyshift['6'] = '^';
keyshift['7'] = '&';
keyshift['8'] = '*';
keyshift['9'] = '(';
keyshift['0'] = ')';
keyshift['-'] = '_';
keyshift['='] = '+';
keyshift[','] = '<';
keyshift['.'] = '>';
keyshift['/'] = '?';
keyshift[';'] = ':';
keyshift['\''] = '"';
keyshift['['] = '{';
keyshift[']'] = '}';
keyshift['`'] = '~';
keyshift['\\'] = '|';
menubound[K_ESCAPE] = true;
for (i=0 ; i<12 ; i++)
menubound[K_F1+i] = true;
//
// register our functions
//
Cmd_AddCommand ("bind",Key_Bind_f);
Cmd_AddCommand ("binddt",Key_Binddt_f);
Cmd_AddCommand ("unbind",Key_Unbind_f);
Cmd_AddCommand ("unbindall",Key_Unbindall_f);
}
/*
===================
Key_Event
Called by the system between frames for both key up and key down events
Should NOT be called during an interrupt!
===================
*/
int lastkey;
double lastkeytime;
int oldkey;
double oldkeytime;
void Key_Event (int key, qboolean down)
{
char *kb;
char cmd[1024];
oldkey = lastkey;
keydown[key] = down;
lastkey = key;
keydown[key] = down;
if (!down)
key_repeats[key] = 0;
key_lastpress = key;
key_count++;
if (key_count <= 0)
{
return; // just catching keys for Con_NotifyBox
}
// update auto-repeat status
if (down)
{
oldkeytime = lastkeytime;
lastkeytime = Sys_FloatTime();
key_repeats[key]++;
if (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1)
{
return; // ignore most autorepeats
}
if (key >= 200 && !keybindings[key])
Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
}
if (key == K_SHIFT)
shift_down = down;
//
// handle escape specialy, so the user can never unbind it
//
if (key == K_ESCAPE)
{
if (!down)
return;
switch (key_dest)
{
case key_message:
Key_Message (key);
break;
case key_menu:
case key_menu_pause:
M_Keydown (key);
break;
case key_game:
case key_console:
console_enabled = false;
M_ToggleMenu_f ();
break;
default:
Sys_Error ("Bad key_dest");
}
return;
}
//
// key up events only generate commands if the game key binding is
// a button command (leading + sign). These will occur even in console mode,
// to keep the character from continuing an action started before a console
// switch. Button commands include the kenum as a parameter, so multiple
// downs can be matched with ups
//
if (!down)
{
kb = keybindings[key];
if (kb && kb[0] == '+')
{
sprintf (cmd, "-%s %i\n", kb+1, key);
Cbuf_AddText (cmd);
}
if (keyshift[key] != key)
{
kb = keybindings[keyshift[key]];
if (kb && kb[0] == '+')
{
sprintf (cmd, "-%s %i\n", kb+1, key);
Cbuf_AddText (cmd);
}
}
return;
}
//
// during demo playback, most keys bring up the main menu
//
if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)
{
M_ToggleMenu_f ();
return;
}
//
// if not a consolekey, send to the interpreter no matter what mode is
//
if ( ((key_dest == key_menu || key_dest == key_menu_pause) && menubound[key])
|| (key_dest == key_console && !consolekeys[key])
|| (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) )
{
if (oldkey == key && ((oldkeytime + 0.3) > lastkeytime))
{
kb = dtbindings[key];
if (kb)
{
if (kb[0] == '+')
{ // button commands add keynum as a parm
sprintf (cmd, kb, key);
Cbuf_AddText (cmd);
}
else
{
Cbuf_AddText (kb);
Cbuf_AddText ("\n");
}
}
oldkey = 0;
oldkeytime = 0;
lastkeytime = 0;
lastkey = 0;
}
kb = keybindings[key];
if (kb)
{
if (kb[0] == '+')
{ // button commands add keynum as a parm
sprintf (cmd, "%s %i\n", kb, key);
Cbuf_AddText (cmd);
}
else
{
Cbuf_AddText (kb);
Cbuf_AddText ("\n");
}
}
return;
}
if (!down)
return; // other systems only care about key down events
if (shift_down)
{
key = keyshift[key];
}
switch (key_dest)
{
case key_message:
Key_Message (key);
break;
case key_menu:
case key_menu_pause:
M_Keydown (key);
break;
case key_game:
case key_console:
Key_Console (key);
break;
default:
Sys_Error ("Bad key_dest");
}
}
/*
===================
Key_ClearStates
===================
*/
void Key_ClearStates (void)
{
int i;
for (i=0 ; i<256 ; i++)
{
keydown[i] = false;
key_repeats[i] = 0;
}
}

137
source/ctr/keys.h Normal file
View file

@ -0,0 +1,137 @@
/*
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.
*/
//
// these are the key numbers that should be passed to Key_Event
//
#define K_TAB 9
#define K_ENTER 13
#define K_ESCAPE 27
#define K_SPACE 32
// normal keys should be passed as lowercased ascii
#define K_BACKSPACE 127
#define K_UPARROW 128
#define K_DOWNARROW 129
#define K_LEFTARROW 130
#define K_RIGHTARROW 131
#define K_ALT 132
#define K_CTRL 133
#define K_SHIFT 134
#define K_F1 135
#define K_F2 136
#define K_F3 137
#define K_F4 138
#define K_F5 139
#define K_F6 140
#define K_F7 141
#define K_F8 142
#define K_F9 143
#define K_F10 144
#define K_F11 145
#define K_F12 146
#define K_INS 147
#define K_DEL 148
#define K_PGDN 149
#define K_PGUP 150
#define K_HOME 151
#define K_END 152
#define K_PAUSE 255
//
// mouse buttons generate virtual keys
//
#define K_MOUSE1 200
#define K_MOUSE2 201
#define K_MOUSE3 202
//
// joystick buttons
//
#define K_JOY1 203
#define K_JOY2 204
#define K_JOY3 205
#define K_JOY4 206
//
// aux keys are for multi-buttoned joysticks to generate so they can use
// the normal binding process
//
#define K_AUX1 207
#define K_AUX2 208
#define K_AUX3 209
#define K_AUX4 210
#define K_AUX5 211
#define K_AUX6 212
#define K_AUX7 213
#define K_AUX8 214
#define K_AUX9 215
#define K_AUX10 216
#define K_AUX11 217
#define K_AUX12 218
#define K_AUX13 219
#define K_AUX14 220
#define K_AUX15 221
#define K_AUX16 222
#define K_AUX17 223
#define K_AUX18 224
#define K_AUX19 225
#define K_AUX20 226
#define K_AUX21 227
#define K_AUX22 228
#define K_AUX23 229
#define K_AUX24 230
#define K_AUX25 231
#define K_AUX26 232
#define K_AUX27 233
#define K_AUX28 234
#define K_AUX29 235
#define K_AUX30 236
#define K_AUX31 237
#define K_AUX32 238
// JACK: Intellimouse(c) Mouse Wheel Support
#define K_MWHEELUP 239
#define K_MWHEELDOWN 240
// naievil -- this is for using the select button for a game key, which is important
#define K_SELECT 241
typedef enum {key_game, key_console, key_message, key_menu, key_menu_pause} keydest_t;
extern keydest_t key_dest;
extern char *keybindings[256];
extern char *dtbindings[256];
extern int key_repeats[256];
extern int key_count; // incremented every key event
extern int key_lastpress;
void Key_Event (int key, qboolean down);
void Key_Init (void);
void Key_WriteBindings (FILE *f);
void Key_SetBinding (int keynum, char *binding);
void Key_WriteDTBindings (FILE *f);
void Key_ClearStates (void);

2415
source/ctr/menu.c Normal file

File diff suppressed because it is too large Load diff

38
source/ctr/menu.h Normal file
View file

@ -0,0 +1,38 @@
/*
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.
*/
//
// the net drivers should just set the apropriate bits in m_activenet,
// instead of having the menu code look through their internal tables
//
#define MNET_IPX 1
#define MNET_TCP 2
extern int m_activenet;
//
// menus
//
void M_Init (void);
void M_Keydown (int key);
void M_Draw (void);
void M_ToggleMenu_f (void);

377
source/ctr/model.h Normal file
View file

@ -0,0 +1,377 @@
/*
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.
*/
#ifndef __MODEL__
#define __MODEL__
#include "modelgen.h"
#include "spritegn.h"
/*
d*_t structures are on-disk representations
m*_t structures are in-memory
*/
/*
==============================================================================
BRUSH MODELS
==============================================================================
*/
//
// in memory representation
//
typedef struct
{
vec3_t position;
} mvertex_t;
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
// plane_t structure
typedef struct mplane_s
{
vec3_t normal;
float dist;
byte type; // for texture axis selection and fast side tests
byte signbits; // signx + signy<<1 + signz<<1
byte pad[2];
} mplane_t;
typedef struct texture_s
{
char name[16];
unsigned width, height;
int anim_total; // total tenths in sequence ( 0 = no)
int anim_min, anim_max; // time for this frame min <=time< max
struct texture_s *anim_next; // in the animation sequence
struct texture_s *alternate_anims; // bmodels in frmae 1 use these
unsigned offsets[MIPLEVELS]; // four mip maps stored
} texture_t;
#define SURF_PLANEBACK 2
#define SURF_DRAWSKY 4
#define SURF_DRAWSPRITE 8
#define SURF_DRAWTURB 0x10
#define SURF_DRAWTILED 0x20
#define SURF_DRAWBACKGROUND 0x40
typedef struct
{
unsigned short v[2];
unsigned int cachededgeoffset;
} medge_t;
typedef struct
{
float vecs[2][4];
float mipadjust;
texture_t *texture;
int flags;
} mtexinfo_t;
typedef struct msurface_s
{
int visframe; // should be drawn when node is crossed
int dlightframe;
int dlightbits;
mplane_t *plane;
int flags;
int firstedge; // look up in model->surfedges[], negative numbers
int numedges; // are backwards edges
// surface generation data
struct surfcache_s *cachespots[MIPLEVELS];
short texturemins[2];
short extents[2];
mtexinfo_t *texinfo;
// lighting info
byte styles[MAXLIGHTMAPS];
byte *samples; // [numstyles*surfsize]
} msurface_t;
typedef struct mnode_s
{
// common with leaf
int contents; // 0, to differentiate from leafs
int visframe; // node needs to be traversed if current
short minmaxs[6]; // for bounding box culling
struct mnode_s *parent;
// node specific
mplane_t *plane;
struct mnode_s *children[2];
unsigned short firstsurface;
unsigned short numsurfaces;
} mnode_t;
typedef struct mleaf_s
{
// common with node
int contents; // wil be a negative contents number
int visframe; // node needs to be traversed if current
short minmaxs[6]; // for bounding box culling
struct mnode_s *parent;
// leaf specific
byte *compressed_vis;
efrag_t *efrags;
msurface_t **firstmarksurface;
int nummarksurfaces;
int key; // BSP sequence number for leaf's contents
byte ambient_sound_level[NUM_AMBIENTS];
} mleaf_t;
typedef struct
{
dclipnode_t *clipnodes;
mplane_t *planes;
int firstclipnode;
int lastclipnode;
vec3_t clip_mins;
vec3_t clip_maxs;
} hull_t;
/*
==============================================================================
SPRITE MODELS
==============================================================================
*/
// FIXME: shorten these?
typedef struct mspriteframe_s
{
int width;
int height;
void *pcachespot; // remove?
float up, down, left, right;
byte pixels[4];
} mspriteframe_t;
typedef struct
{
int numframes;
float *intervals;
mspriteframe_t *frames[1];
} mspritegroup_t;
typedef struct
{
spriteframetype_t type;
mspriteframe_t *frameptr;
} mspriteframedesc_t;
typedef struct
{
int type;
int maxwidth;
int maxheight;
int numframes;
float beamlength; // remove?
void *cachespot; // remove?
mspriteframedesc_t frames[1];
} msprite_t;
/*
==============================================================================
ALIAS MODELS
Alias models are position independent, so the cache manager can move them.
==============================================================================
*/
typedef struct
{
aliasframetype_t type;
trivertx_t bboxmin;
trivertx_t bboxmax;
int frame;
char name[16];
} maliasframedesc_t;
typedef struct
{
aliasskintype_t type;
void *pcachespot;
int skin;
} maliasskindesc_t;
typedef struct
{
trivertx_t bboxmin;
trivertx_t bboxmax;
int frame;
} maliasgroupframedesc_t;
typedef struct
{
int numframes;
int intervals;
maliasgroupframedesc_t frames[1];
} maliasgroup_t;
typedef struct
{
int numskins;
int intervals;
maliasskindesc_t skindescs[1];
} maliasskingroup_t;
typedef struct mtriangle_s {
int facesfront;
int vertindex[3];
} mtriangle_t;
typedef struct {
int model;
int stverts;
int skindesc;
int triangles;
maliasframedesc_t frames[1];
} aliashdr_t;
//===================================================================
//
// Whole model
//
typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;
#define EF_ROCKET 1 // leave a trail
#define EF_GRENADE 2 // leave a trail
#define EF_GIB 4 // leave a trail
#define EF_ROTATE 8 // rotate (bonus items)
#define EF_TRACER 16 // green split trail
#define EF_ZOMGIB 32 // small blood trail
#define EF_TRACER2 64 // orange split trail + rotate
#define EF_TRACER3 128 // purple trail
typedef struct model_s
{
char name[MAX_QPATH];
qboolean needload; // bmodels and sprites don't cache normally
modtype_t type;
int numframes;
synctype_t synctype;
int flags;
//
// volume occupied by the model
//
vec3_t mins, maxs;
float radius;
//
// brush model
//
int firstmodelsurface, nummodelsurfaces;
int numsubmodels;
dmodel_t *submodels;
int numplanes;
mplane_t *planes;
int numleafs; // number of visible leafs, not counting 0
mleaf_t *leafs;
int numvertexes;
mvertex_t *vertexes;
int numedges;
medge_t *edges;
int numnodes;
mnode_t *nodes;
int numtexinfo;
mtexinfo_t *texinfo;
int numsurfaces;
msurface_t *surfaces;
int numsurfedges;
int *surfedges;
int numclipnodes;
dclipnode_t *clipnodes;
int nummarksurfaces;
msurface_t **marksurfaces;
hull_t hulls[MAX_MAP_HULLS];
int numtextures;
texture_t **textures;
byte *visdata;
byte *lightdata;
char *entities;
//
// additional model data
//
cache_user_t cache; // only access through Mod_Extradata
} model_t;
//============================================================================
void Mod_Init (void);
void Mod_ClearAll (void);
model_t *Mod_ForName (char *name, qboolean crash);
void *Mod_Extradata (model_t *mod); // handles caching
void Mod_TouchModel (char *name);
mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model);
#endif // __MODEL__

134
source/ctr/modelgen.h Normal file
View file

@ -0,0 +1,134 @@
/*
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.
*/
//
// modelgen.h: header file for model generation program
//
// *********************************************************
// * This file must be identical in the modelgen directory *
// * and in the Quake directory, because it's used to *
// * pass data from one to the other via model files. *
// *********************************************************
#ifdef INCLUDELIBS
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "cmdlib.h"
#include "scriplib.h"
#include "trilib.h"
#include "lbmlib.h"
#include "mathlib.h"
#endif
#define ALIAS_VERSION 6
#define ALIAS_ONSEAM 0x0020
// must match definition in spritegn.h
#ifndef SYNCTYPE_T
#define SYNCTYPE_T
typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
#endif
typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t;
typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t;
typedef struct {
int ident;
int version;
vec3_t scale;
vec3_t scale_origin;
float boundingradius;
vec3_t eyeposition;
int numskins;
int skinwidth;
int skinheight;
int numverts;
int numtris;
int numframes;
synctype_t synctype;
int flags;
float size;
} mdl_t;
// TODO: could be shorts
typedef struct {
int onseam;
int s;
int t;
} stvert_t;
typedef struct dtriangle_s {
int facesfront;
int vertindex[3];
} dtriangle_t;
#define DT_FACES_FRONT 0x0010
// This mirrors trivert_t in trilib.h, is present so Quake knows how to
// load this data
typedef struct {
byte v[3];
byte lightnormalindex;
} trivertx_t;
typedef struct {
trivertx_t bboxmin; // lightnormal isn't used
trivertx_t bboxmax; // lightnormal isn't used
char name[16]; // frame name from grabbing
} daliasframe_t;
typedef struct {
int numframes;
trivertx_t bboxmin; // lightnormal isn't used
trivertx_t bboxmax; // lightnormal isn't used
} daliasgroup_t;
typedef struct {
int numskins;
} daliasskingroup_t;
typedef struct {
float interval;
} daliasinterval_t;
typedef struct {
float interval;
} daliasskininterval_t;
typedef struct {
int type;
} daliasframetype_t;
typedef struct {
int type;
} daliasskintype_t;
#define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I')
// little-endian "IDPO"

337
source/ctr/net.h Normal file
View file

@ -0,0 +1,337 @@
/*
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.
*/
// net.h -- quake's interface to the networking layer
struct qsockaddr
{
short sa_family;
unsigned char sa_data[14];
};
#define NET_NAMELEN 64
#define NET_MAXMESSAGE 16384
#define NET_HEADERSIZE (2 * sizeof(unsigned int))
#define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE)
// NetHeader flags
#define NETFLAG_LENGTH_MASK 0x0000ffff
#define NETFLAG_DATA 0x00010000
#define NETFLAG_ACK 0x00020000
#define NETFLAG_NAK 0x00040000
#define NETFLAG_EOM 0x00080000
#define NETFLAG_UNRELIABLE 0x00100000
#define NETFLAG_CTL 0x80000000
#define NET_PROTOCOL_VERSION 3
// This is the network info/connection protocol. It is used to find Quake
// servers, get info about them, and connect to them. Once connected, the
// Quake game protocol (documented elsewhere) is used.
//
//
// General notes:
// game_name is currently always "QUAKE", but is there so this same protocol
// can be used for future games as well; can you say Quake2?
//
// CCREQ_CONNECT
// string game_name "QUAKE"
// byte net_protocol_version NET_PROTOCOL_VERSION
//
// CCREQ_SERVER_INFO
// string game_name "QUAKE"
// byte net_protocol_version NET_PROTOCOL_VERSION
//
// CCREQ_PLAYER_INFO
// byte player_number
//
// CCREQ_RULE_INFO
// string rule
//
//
//
// CCREP_ACCEPT
// long port
//
// CCREP_REJECT
// string reason
//
// CCREP_SERVER_INFO
// string server_address
// string host_name
// string level_name
// byte current_players
// byte max_players
// byte protocol_version NET_PROTOCOL_VERSION
//
// CCREP_PLAYER_INFO
// byte player_number
// string name
// long colors
// long frags
// long connect_time
// string address
//
// CCREP_RULE_INFO
// string rule
// string value
// note:
// There are two address forms used above. The short form is just a
// port number. The address that goes along with the port is defined as
// "whatever address you receive this reponse from". This lets us use
// the host OS to solve the problem of multiple host addresses (possibly
// with no routing between them); the host will use the right address
// when we reply to the inbound connection request. The long from is
// a full address and port in a string. It is used for returning the
// address of a server that is not running locally.
#define CCREQ_CONNECT 0x01
#define CCREQ_SERVER_INFO 0x02
#define CCREQ_PLAYER_INFO 0x03
#define CCREQ_RULE_INFO 0x04
#define CCREP_ACCEPT 0x81
#define CCREP_REJECT 0x82
#define CCREP_SERVER_INFO 0x83
#define CCREP_PLAYER_INFO 0x84
#define CCREP_RULE_INFO 0x85
typedef struct qsocket_s
{
struct qsocket_s *next;
double connecttime;
double lastMessageTime;
double lastSendTime;
qboolean disconnected;
qboolean canSend;
qboolean sendNext;
int driver;
int landriver;
int socket;
void *driverdata;
unsigned int ackSequence;
unsigned int sendSequence;
unsigned int unreliableSendSequence;
int sendMessageLength;
byte sendMessage [NET_MAXMESSAGE];
unsigned int receiveSequence;
unsigned int unreliableReceiveSequence;
int receiveMessageLength;
byte receiveMessage [NET_MAXMESSAGE];
struct qsockaddr addr;
char address[NET_NAMELEN];
} qsocket_t;
extern qsocket_t *net_activeSockets;
extern qsocket_t *net_freeSockets;
extern int net_numsockets;
typedef struct
{
char *name;
qboolean initialized;
int controlSock;
int (*Init) (void);
void (*Shutdown) (void);
void (*Listen) (qboolean state);
int (*OpenSocket) (int port);
int (*CloseSocket) (int socket);
int (*Connect) (int socket, struct qsockaddr *addr);
int (*CheckNewConnections) (void);
int (*Read) (int socket, byte *buf, int len, struct qsockaddr *addr);
int (*Write) (int socket, byte *buf, int len, struct qsockaddr *addr);
int (*Broadcast) (int socket, byte *buf, int len);
char * (*AddrToString) (struct qsockaddr *addr);
int (*StringToAddr) (char *string, struct qsockaddr *addr);
int (*GetSocketAddr) (int socket, struct qsockaddr *addr);
int (*GetNameFromAddr) (struct qsockaddr *addr, char *name);
int (*GetAddrFromName) (char *name, struct qsockaddr *addr);
int (*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2);
int (*GetSocketPort) (struct qsockaddr *addr);
int (*SetSocketPort) (struct qsockaddr *addr, int port);
} net_landriver_t;
#define MAX_NET_DRIVERS 8
extern int net_numlandrivers;
extern net_landriver_t net_landrivers[MAX_NET_DRIVERS];
typedef struct
{
char *name;
qboolean initialized;
int (*Init) (void);
void (*Listen) (qboolean state);
void (*SearchForHosts) (qboolean xmit);
qsocket_t *(*Connect) (char *host);
qsocket_t *(*CheckNewConnections) (void);
int (*QGetMessage) (qsocket_t *sock);
int (*QSendMessage) (qsocket_t *sock, sizebuf_t *data);
int (*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data);
qboolean (*CanSendMessage) (qsocket_t *sock);
qboolean (*CanSendUnreliableMessage) (qsocket_t *sock);
void (*Close) (qsocket_t *sock);
void (*Shutdown) (void);
int controlSock;
} net_driver_t;
extern int net_numdrivers;
extern net_driver_t net_drivers[MAX_NET_DRIVERS];
extern int DEFAULTnet_hostport;
extern int net_hostport;
extern int net_driverlevel;
extern cvar_t hostname;
extern char playername[];
extern int playercolor;
extern int messagesSent;
extern int messagesReceived;
extern int unreliableMessagesSent;
extern int unreliableMessagesReceived;
qsocket_t *NET_NewQSocket (void);
void NET_FreeQSocket(qsocket_t *);
double SetNetTime(void);
#define HOSTCACHESIZE 8
typedef struct
{
char name[16];
char map[16];
char cname[32];
int users;
int maxusers;
int driver;
int ldriver;
struct qsockaddr addr;
} hostcache_t;
extern int hostCacheCount;
extern hostcache_t hostcache[HOSTCACHESIZE];
#if !defined(_WIN32 ) && !defined (__linux__) && !defined (__sun__)
#ifndef htonl
extern unsigned long htonl (unsigned long hostlong);
#endif
#ifndef htons
extern unsigned short htons (unsigned short hostshort);
#endif
#ifndef ntohl
extern unsigned long ntohl (unsigned long netlong);
#endif
#ifndef ntohs
extern unsigned short ntohs (unsigned short netshort);
#endif
#endif
#ifdef IDGODS
qboolean IsID(struct qsockaddr *addr);
#endif
//============================================================================
//
// public network functions
//
//============================================================================
extern double net_time;
extern sizebuf_t net_message;
extern int net_activeconnections;
void NET_Init (void);
void NET_Shutdown (void);
struct qsocket_s *NET_CheckNewConnections (void);
// returns a new connection number if there is one pending, else -1
struct qsocket_s *NET_Connect (char *host);
// called by client to connect to a host. Returns -1 if not able to
qboolean NET_CanSendMessage (qsocket_t *sock);
// Returns true or false if the given qsocket can currently accept a
// message to be transmitted.
int NET_GetMessage (struct qsocket_s *sock);
// returns data in net_message sizebuf
// returns 0 if no data is waiting
// returns 1 if a message was received
// returns 2 if an unreliable message was received
// returns -1 if the connection died
int NET_SendMessage (struct qsocket_s *sock, sizebuf_t *data);
int NET_SendUnreliableMessage (struct qsocket_s *sock, sizebuf_t *data);
// returns 0 if the message connot be delivered reliably, but the connection
// is still considered valid
// returns 1 if the message was sent properly
// returns -1 if the connection died
int NET_SendToAll(sizebuf_t *data, int blocktime);
// This is a reliable *blocking* send to all attached clients.
void NET_Close (struct qsocket_s *sock);
// if a dead connection is returned by a get or send function, this function
// should be called when it is convenient
// Server calls when a client is kicked off for a game related misbehavior
// like an illegal protocal conversation. Client calls when disconnecting
// from a server.
// A netcon_t number will not be reused until this function is called for it
void NET_Poll(void);
typedef struct _PollProcedure
{
struct _PollProcedure *next;
double nextTime;
void (*procedure)();
void *arg;
} PollProcedure;
void SchedulePollProcedure(PollProcedure *pp, double timeOffset);
extern qboolean serialAvailable;
extern qboolean ipxAvailable;
extern qboolean tcpipAvailable;
extern char my_ipx_address[NET_NAMELEN];
extern char my_tcpip_address[NET_NAMELEN];
extern void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
extern void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
extern void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
extern void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
extern qboolean slistInProgress;
extern qboolean slistSilent;
extern qboolean slistLocal;
void NET_Slist_f (void);

93
source/ctr/net_bsd.c Normal file
View file

@ -0,0 +1,93 @@
/*
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.
*/
#include "../quakedef.h"
#include "../net_loop.h"
#include "net_dgrm.h"
net_driver_t net_drivers[MAX_NET_DRIVERS] =
{
{
"Loopback",
false,
Loop_Init,
Loop_Listen,
Loop_SearchForHosts,
Loop_Connect,
Loop_CheckNewConnections,
Loop_GetMessage,
Loop_SendMessage,
Loop_SendUnreliableMessage,
Loop_CanSendMessage,
Loop_CanSendUnreliableMessage,
Loop_Close,
Loop_Shutdown
}
,
{
"Datagram",
false,
Datagram_Init,
Datagram_Listen,
Datagram_SearchForHosts,
Datagram_Connect,
Datagram_CheckNewConnections,
Datagram_GetMessage,
Datagram_SendMessage,
Datagram_SendUnreliableMessage,
Datagram_CanSendMessage,
Datagram_CanSendUnreliableMessage,
Datagram_Close,
Datagram_Shutdown
}
};
int net_numdrivers = 2;
#include "net_udp.h"
net_landriver_t net_landrivers[MAX_NET_DRIVERS] =
{
{
"UDP",
false,
0,
UDP_Init,
UDP_Shutdown,
UDP_Listen,
UDP_OpenSocket,
UDP_CloseSocket,
UDP_Connect,
UDP_CheckNewConnections,
UDP_Read,
UDP_Write,
UDP_Broadcast,
UDP_AddrToString,
UDP_StringToAddr,
UDP_GetSocketAddr,
UDP_GetNameFromAddr,
UDP_GetAddrFromName,
UDP_AddrCompare,
UDP_GetSocketPort,
UDP_SetSocketPort
}
};
int net_numlandrivers = 1;

1373
source/ctr/net_dgrm.c Normal file

File diff suppressed because it is too large Load diff

34
source/ctr/net_dgrm.h Normal file
View file

@ -0,0 +1,34 @@
/*
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.
*/
// net_dgrm.h
int Datagram_Init (void);
void Datagram_Listen (qboolean state);
void Datagram_SearchForHosts (qboolean xmit);
qsocket_t *Datagram_Connect (char *host);
qsocket_t *Datagram_CheckNewConnections (void);
int Datagram_GetMessage (qsocket_t *sock);
int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data);
int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
qboolean Datagram_CanSendMessage (qsocket_t *sock);
qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock);
void Datagram_Close (qsocket_t *sock);
void Datagram_Shutdown (void);

997
source/ctr/net_main.c Normal file
View file

@ -0,0 +1,997 @@
/*
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.
*/
// net_main.c
#include "../quakedef.h"
#include "../net_vcr.h"
qsocket_t *net_activeSockets = NULL;
qsocket_t *net_freeSockets = NULL;
int net_numsockets = 0;
qboolean serialAvailable = false;
qboolean ipxAvailable = false;
qboolean tcpipAvailable = false;
int net_hostport;
int DEFAULTnet_hostport = 26000;
char my_ipx_address[NET_NAMELEN];
char my_tcpip_address[NET_NAMELEN];
void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
static qboolean listening = false;
qboolean slistInProgress = false;
qboolean slistSilent = false;
qboolean slistLocal = true;
static double slistStartTime;
static int slistLastShown;
static void Slist_Send(void);
static void Slist_Poll(void);
PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
sizebuf_t net_message;
int net_activeconnections = 0;
int messagesSent = 0;
int messagesReceived = 0;
int unreliableMessagesSent = 0;
int unreliableMessagesReceived = 0;
cvar_t net_messagetimeout = {"net_messagetimeout","300"};
cvar_t hostname = {"hostname", "UNNAMED"};
qboolean configRestored = false;
cvar_t config_com_port = {"_config_com_port", "0x3f8", true};
cvar_t config_com_irq = {"_config_com_irq", "4", true};
cvar_t config_com_baud = {"_config_com_baud", "57600", true};
cvar_t config_com_modem = {"_config_com_modem", "1", true};
cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true};
cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true};
cvar_t config_modem_init = {"_config_modem_init", "", true};
cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true};
#ifdef IDGODS
cvar_t idgods = {"idgods", "0"};
#endif
int vcrFile = -1;
qboolean recording = false;
// these two macros are to make the code more readable
#define sfunc net_drivers[sock->driver]
#define dfunc net_drivers[net_driverlevel]
int net_driverlevel;
double net_time;
double SetNetTime(void)
{
net_time = Sys_FloatTime();
return net_time;
}
/*
===================
NET_NewQSocket
Called by drivers when a new communications endpoint is required
The sequence and buffer fields will be filled in properly
===================
*/
qsocket_t *NET_NewQSocket (void)
{
qsocket_t *sock;
if (net_freeSockets == NULL)
return NULL;
if (net_activeconnections >= svs.maxclients)
return NULL;
// get one from free list
sock = net_freeSockets;
net_freeSockets = sock->next;
// add it to active list
sock->next = net_activeSockets;
net_activeSockets = sock;
sock->disconnected = false;
sock->connecttime = net_time;
Q_strcpy (sock->address,"UNSET ADDRESS");
sock->driver = net_driverlevel;
sock->socket = 0;
sock->driverdata = NULL;
sock->canSend = true;
sock->sendNext = false;
sock->lastMessageTime = net_time;
sock->ackSequence = 0;
sock->sendSequence = 0;
sock->unreliableSendSequence = 0;
sock->sendMessageLength = 0;
sock->receiveSequence = 0;
sock->unreliableReceiveSequence = 0;
sock->receiveMessageLength = 0;
return sock;
}
void NET_FreeQSocket(qsocket_t *sock)
{
qsocket_t *s;
// remove it from active list
if (sock == net_activeSockets)
net_activeSockets = net_activeSockets->next;
else
{
for (s = net_activeSockets; s; s = s->next)
if (s->next == sock)
{
s->next = sock->next;
break;
}
if (!s)
Sys_Error ("NET_FreeQSocket: not active\n");
}
// add it to free list
sock->next = net_freeSockets;
net_freeSockets = sock;
sock->disconnected = true;
}
static void NET_Listen_f (void)
{
if (Cmd_Argc () != 2)
{
Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
return;
}
listening = Q_atoi(Cmd_Argv(1)) ? true : false;
for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
{
if (net_drivers[net_driverlevel].initialized == false)
continue;
dfunc.Listen (listening);
}
}
static void MaxPlayers_f (void)
{
int n;
if (Cmd_Argc () != 2)
{
Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
return;
}
if (sv.active)
{
Con_Printf ("maxplayers can not be changed while a server is running.\n");
return;
}
n = Q_atoi(Cmd_Argv(1));
if (n < 1)
n = 1;
if (n > svs.maxclientslimit)
{
n = svs.maxclientslimit;
Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
}
if ((n == 1) && listening)
Cbuf_AddText ("listen 0\n");
if ((n > 1) && (!listening))
Cbuf_AddText ("listen 1\n");
svs.maxclients = n;
if (n == 1)
Cvar_Set ("deathmatch", "0");
else
Cvar_Set ("deathmatch", "1");
}
static void NET_Port_f (void)
{
int n;
if (Cmd_Argc () != 2)
{
Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
return;
}
n = Q_atoi(Cmd_Argv(1));
if (n < 1 || n > 65534)
{
Con_Printf ("Bad value, must be between 1 and 65534\n");
return;
}
DEFAULTnet_hostport = n;
net_hostport = n;
if (listening)
{
// force a change to the new port
Cbuf_AddText ("listen 0\n");
Cbuf_AddText ("listen 1\n");
}
}
static void PrintSlistHeader(void)
{
Con_Printf("Server Map Users\n");
Con_Printf("--------------- --------------- -----\n");
slistLastShown = 0;
}
static void PrintSlist(void)
{
int n;
for (n = slistLastShown; n < hostCacheCount; n++)
{
if (hostcache[n].maxusers)
Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
else
Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
}
slistLastShown = n;
}
static void PrintSlistTrailer(void)
{
if (hostCacheCount)
Con_Printf("== end list ==\n\n");
else
Con_Printf("No Quake servers found.\n\n");
}
void NET_Slist_f (void)
{
if (slistInProgress)
return;
if (! slistSilent)
{
Con_Printf("Looking for Quake servers...\n");
PrintSlistHeader();
}
slistInProgress = true;
slistStartTime = Sys_FloatTime();
SchedulePollProcedure(&slistSendProcedure, 0.0);
SchedulePollProcedure(&slistPollProcedure, 0.1);
hostCacheCount = 0;
}
static void Slist_Send(void)
{
for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
{
if (!slistLocal && net_driverlevel == 0)
continue;
if (net_drivers[net_driverlevel].initialized == false)
continue;
dfunc.SearchForHosts (true);
}
if ((Sys_FloatTime() - slistStartTime) < 0.5)
SchedulePollProcedure(&slistSendProcedure, 0.75);
}
static void Slist_Poll(void)
{
for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
{
if (!slistLocal && net_driverlevel == 0)
continue;
if (net_drivers[net_driverlevel].initialized == false)
continue;
dfunc.SearchForHosts (false);
}
if (! slistSilent)
PrintSlist();
if ((Sys_FloatTime() - slistStartTime) < 1.5)
{
SchedulePollProcedure(&slistPollProcedure, 0.1);
return;
}
if (! slistSilent)
PrintSlistTrailer();
slistInProgress = false;
slistSilent = false;
slistLocal = true;
}
/*
===================
NET_Connect
===================
*/
int hostCacheCount = 0;
hostcache_t hostcache[HOSTCACHESIZE];
qsocket_t *NET_Connect (char *host)
{
qsocket_t *ret;
int n;
int numdrivers = net_numdrivers;
SetNetTime();
if (host && *host == 0)
host = NULL;
if (host)
{
if (Q_strcasecmp (host, "local") == 0)
{
numdrivers = 1;
goto JustDoIt;
}
if (hostCacheCount)
{
for (n = 0; n < hostCacheCount; n++)
if (Q_strcasecmp (host, hostcache[n].name) == 0)
{
host = hostcache[n].cname;
break;
}
if (n < hostCacheCount)
goto JustDoIt;
}
}
slistSilent = host ? true : false;
NET_Slist_f ();
while(slistInProgress)
NET_Poll();
if (host == NULL)
{
if (hostCacheCount != 1)
return NULL;
host = hostcache[0].cname;
Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
}
if (hostCacheCount)
for (n = 0; n < hostCacheCount; n++)
if (Q_strcasecmp (host, hostcache[n].name) == 0)
{
host = hostcache[n].cname;
break;
}
JustDoIt:
for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
{
if (net_drivers[net_driverlevel].initialized == false)
continue;
ret = dfunc.Connect (host);
if (ret)
return ret;
}
if (host)
{
Con_Printf("\n");
PrintSlistHeader();
PrintSlist();
PrintSlistTrailer();
}
return NULL;
}
/*
===================
NET_CheckNewConnections
===================
*/
struct
{
double time;
int op;
long session;
} vcrConnect;
qsocket_t *NET_CheckNewConnections (void)
{
qsocket_t *ret;
SetNetTime();
for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
{
if (net_drivers[net_driverlevel].initialized == false)
continue;
if (net_driverlevel && listening == false)
continue;
ret = dfunc.CheckNewConnections ();
if (ret)
{
if (recording)
{
vcrConnect.time = host_time;
vcrConnect.op = VCR_OP_CONNECT;
vcrConnect.session = (long)ret;
Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);
}
return ret;
}
}
if (recording)
{
vcrConnect.time = host_time;
vcrConnect.op = VCR_OP_CONNECT;
vcrConnect.session = 0;
Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
}
return NULL;
}
/*
===================
NET_Close
===================
*/
void NET_Close (qsocket_t *sock)
{
if (!sock)
return;
if (sock->disconnected)
return;
SetNetTime();
// call the driver_Close function
sfunc.Close (sock);
NET_FreeQSocket(sock);
}
/*
=================
NET_GetMessage
If there is a complete message, return it in net_message
returns 0 if no data is waiting
returns 1 if a message was received
returns -1 if connection is invalid
=================
*/
struct
{
double time;
int op;
long session;
int ret;
int len;
} vcrGetMessage;
extern void PrintStats(qsocket_t *s);
int NET_GetMessage (qsocket_t *sock)
{
int ret;
if (!sock)
return -1;
if (sock->disconnected)
{
Con_Printf("NET_GetMessage: disconnected socket\n");
return -1;
}
SetNetTime();
ret = sfunc.QGetMessage(sock);
// see if this connection has timed out
if (ret == 0 && sock->driver)
{
if (net_time - sock->lastMessageTime > net_messagetimeout.value)
{
NET_Close(sock);
return -1;
}
}
if (ret > 0)
{
if (sock->driver)
{
sock->lastMessageTime = net_time;
if (ret == 1)
messagesReceived++;
else if (ret == 2)
unreliableMessagesReceived++;
}
if (recording)
{
vcrGetMessage.time = host_time;
vcrGetMessage.op = VCR_OP_GETMESSAGE;
vcrGetMessage.session = (long)sock;
vcrGetMessage.ret = ret;
vcrGetMessage.len = net_message.cursize;
Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
}
}
else
{
if (recording)
{
vcrGetMessage.time = host_time;
vcrGetMessage.op = VCR_OP_GETMESSAGE;
vcrGetMessage.session = (long)sock;
vcrGetMessage.ret = ret;
Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
}
}
return ret;
}
/*
==================
NET_SendMessage
Try to send a complete length+message unit over the reliable stream.
returns 0 if the message cannot be delivered reliably, but the connection
is still considered valid
returns 1 if the message was sent properly
returns -1 if the connection died
==================
*/
struct
{
double time;
int op;
long session;
int r;
} vcrSendMessage;
int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
{
int r;
if (!sock)
return -1;
if (sock->disconnected)
{
Con_Printf("NET_SendMessage: disconnected socket\n");
return -1;
}
SetNetTime();
r = sfunc.QSendMessage(sock, data);
if (r == 1 && sock->driver)
messagesSent++;
if (recording)
{
vcrSendMessage.time = host_time;
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
vcrSendMessage.session = (long)sock;
vcrSendMessage.r = r;
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
}
return r;
}
int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
{
int r;
if (!sock)
return -1;
if (sock->disconnected)
{
Con_Printf("NET_SendMessage: disconnected socket\n");
return -1;
}
SetNetTime();
r = sfunc.SendUnreliableMessage(sock, data);
if (r == 1 && sock->driver)
unreliableMessagesSent++;
if (recording)
{
vcrSendMessage.time = host_time;
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
vcrSendMessage.session = (long)sock;
vcrSendMessage.r = r;
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
}
return r;
}
/*
==================
NET_CanSendMessage
Returns true or false if the given qsocket can currently accept a
message to be transmitted.
==================
*/
qboolean NET_CanSendMessage (qsocket_t *sock)
{
int r;
if (!sock)
return false;
if (sock->disconnected)
return false;
SetNetTime();
r = sfunc.CanSendMessage(sock);
if (recording)
{
vcrSendMessage.time = host_time;
vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
vcrSendMessage.session = (long)sock;
vcrSendMessage.r = r;
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
}
return r;
}
int NET_SendToAll(sizebuf_t *data, int blocktime)
{
double start;
int i;
int count = 0;
qboolean state1 [MAX_SCOREBOARD];
qboolean state2 [MAX_SCOREBOARD];
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
{
if (!host_client->netconnection)
continue;
if (host_client->active)
{
if (host_client->netconnection->driver == 0)
{
NET_SendMessage(host_client->netconnection, data);
state1[i] = true;
state2[i] = true;
continue;
}
count++;
state1[i] = false;
state2[i] = false;
}
else
{
state1[i] = true;
state2[i] = true;
}
}
start = Sys_FloatTime();
while (count)
{
count = 0;
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
{
if (! state1[i])
{
if (NET_CanSendMessage (host_client->netconnection))
{
state1[i] = true;
NET_SendMessage(host_client->netconnection, data);
}
else
{
NET_GetMessage (host_client->netconnection);
}
count++;
continue;
}
if (! state2[i])
{
if (NET_CanSendMessage (host_client->netconnection))
{
state2[i] = true;
}
else
{
NET_GetMessage (host_client->netconnection);
}
count++;
continue;
}
}
if ((Sys_FloatTime() - start) > blocktime)
break;
}
return count;
}
//=============================================================================
/*
====================
NET_Init
====================
*/
void NET_Init (void)
{
int i;
int controlSocket;
qsocket_t *s;
if (COM_CheckParm("-playback"))
{
net_numdrivers = 1;
net_drivers[0].Init = VCR_Init;
}
if (COM_CheckParm("-record"))
recording = true;
i = COM_CheckParm ("-port");
if (!i)
i = COM_CheckParm ("-udpport");
if (!i)
i = COM_CheckParm ("-ipxport");
if (i)
{
if (i < com_argc-1)
DEFAULTnet_hostport = Q_atoi (com_argv[i+1]);
else
Sys_Error ("NET_Init: you must specify a number after -port");
}
net_hostport = DEFAULTnet_hostport;
if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
listening = true;
net_numsockets = svs.maxclientslimit;
if (cls.state != ca_dedicated)
net_numsockets++;
SetNetTime();
for (i = 0; i < net_numsockets; i++)
{
s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
s->next = net_freeSockets;
net_freeSockets = s;
s->disconnected = true;
}
// allocate space for network message buffer
SZ_Alloc (&net_message, NET_MAXMESSAGE);
Cvar_RegisterVariable (&net_messagetimeout);
Cvar_RegisterVariable (&hostname);
Cvar_RegisterVariable (&config_com_port);
Cvar_RegisterVariable (&config_com_irq);
Cvar_RegisterVariable (&config_com_baud);
Cvar_RegisterVariable (&config_com_modem);
Cvar_RegisterVariable (&config_modem_dialtype);
Cvar_RegisterVariable (&config_modem_clear);
Cvar_RegisterVariable (&config_modem_init);
Cvar_RegisterVariable (&config_modem_hangup);
#ifdef IDGODS
Cvar_RegisterVariable (&idgods);
#endif
Cmd_AddCommand ("slist", NET_Slist_f);
Cmd_AddCommand ("listen", NET_Listen_f);
Cmd_AddCommand ("maxplayers", MaxPlayers_f);
Cmd_AddCommand ("port", NET_Port_f);
// initialize all the drivers
for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
{
controlSocket = net_drivers[net_driverlevel].Init();
if (controlSocket == -1)
continue;
net_drivers[net_driverlevel].initialized = true;
net_drivers[net_driverlevel].controlSock = controlSocket;
if (listening)
net_drivers[net_driverlevel].Listen (true);
}
if (*my_ipx_address)
Con_DPrintf("IPX address %s\n", my_ipx_address);
if (*my_tcpip_address)
Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
}
/*
====================
NET_Shutdown
====================
*/
void NET_Shutdown (void)
{
qsocket_t *sock;
SetNetTime();
for (sock = net_activeSockets; sock; sock = sock->next)
NET_Close(sock);
//
// shutdown the drivers
//
for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
{
if (net_drivers[net_driverlevel].initialized == true)
{
net_drivers[net_driverlevel].Shutdown ();
net_drivers[net_driverlevel].initialized = false;
}
}
if (vcrFile != -1)
{
Con_Printf ("Closing vcrfile.\n");
Sys_FileClose(vcrFile);
}
}
static PollProcedure *pollProcedureList = NULL;
void NET_Poll(void)
{
PollProcedure *pp;
qboolean useModem;
if (!configRestored)
{
if (serialAvailable)
{
if (config_com_modem.value == 1.0)
useModem = true;
else
useModem = false;
SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
}
configRestored = true;
}
SetNetTime();
for (pp = pollProcedureList; pp; pp = pp->next)
{
if (pp->nextTime > net_time)
break;
pollProcedureList = pp->next;
pp->procedure(pp->arg);
}
}
void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
{
PollProcedure *pp, *prev;
proc->nextTime = Sys_FloatTime() + timeOffset;
for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
{
if (pp->nextTime >= proc->nextTime)
break;
prev = pp;
}
if (prev == NULL)
{
proc->next = pollProcedureList;
pollProcedureList = proc;
return;
}
proc->next = pp;
prev->next = proc;
}
#ifdef IDGODS
#define IDNET 0xc0f62800
qboolean IsID(struct qsockaddr *addr)
{
if (idgods.value == 0.0)
return false;
if (addr->sa_family != 2)
return false;
if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
return true;
return false;
}
#endif

39
source/ctr/net_udp.h 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.
*/
// net_udp.h
int UDP_Init (void);
void UDP_Shutdown (void);
void UDP_Listen (qboolean state);
int UDP_OpenSocket (int port);
int UDP_CloseSocket (int socket);
int UDP_Connect (int socket, struct qsockaddr *addr);
int UDP_CheckNewConnections (void);
int UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr);
int UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr);
int UDP_Broadcast (int socket, byte *buf, int len);
char *UDP_AddrToString (struct qsockaddr *addr);
int UDP_StringToAddr (char *string, struct qsockaddr *addr);
int UDP_GetSocketAddr (int socket, struct qsockaddr *addr);
int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);
int UDP_GetAddrFromName (char *name, struct qsockaddr *addr);
int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
int UDP_GetSocketPort (struct qsockaddr *addr);
int UDP_SetSocketPort (struct qsockaddr *addr, int port);

445
source/ctr/net_udpctr.c Normal file
View file

@ -0,0 +1,445 @@
/*
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.
*/
// net_udp.c
#include "../quakedef.h"
#include "net_udp.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <3ds.h>
#include <sys/fcntl.h>
inline uint32_t htonl(uint32_t hostshort)
{
return __builtin_bswap32(hostshort);
}
inline uint16_t htons(uint16_t hostshort)
{
return __builtin_bswap16(hostshort);
}
inline uint32_t ntohl(uint32_t netlong)
{
return __builtin_bswap32(netlong);
}
inline uint16_t ntohs(uint16_t netshort)
{
return __builtin_bswap16(netshort);
}
#define SOC_BUFFERSIZE 0x100000
#define SOC_ALIGN 0x1000
static u32 *SOC_buffer = NULL;
extern int close (int);
extern cvar_t hostname;
static int net_acceptsocket = -1; // socket for fielding new connections
static int net_controlsocket;
static int net_broadcastsocket = 0;
static struct qsockaddr broadcastaddr;
static unsigned long myAddr;
#include "net_udp.h"
//=============================================================================
int UDP_Init (void)
{
struct hostent *local;
char buff[15];
struct qsockaddr addr;
char *colon;
int ret;
if (COM_CheckParm ("-noudp"))
return -1;
SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
if(SOC_buffer == NULL)
{
Sys_Error("Failed to allocate SOC_Buffer\n");
}
ret = socInit(SOC_buffer, SOC_BUFFERSIZE);
if(ret != 0)
{
free(SOC_buffer);
return -1;
}
myAddr = gethostid();
// if the quake hostname isn't set, set it to the machine name
if (strcmp(hostname.string, "UNNAMED") == 0)
{
Cvar_Set ("hostname", "3ds");
}
if ((net_controlsocket = UDP_OpenSocket (5000)) == -1) //Passing 0 causes function to fail on 3DS
{
socExit();
free(SOC_buffer);
return -1;
}
((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport);
UDP_GetSocketAddr (net_controlsocket, &addr);
Q_strcpy(my_tcpip_address, UDP_AddrToString (&addr));
colon = Q_strrchr (my_tcpip_address, ':');
if (colon)
*colon = 0;
Con_Printf("UDP Initialized\n");
tcpipAvailable = true;
return net_controlsocket;
}
//=============================================================================
void UDP_Shutdown (void)
{
UDP_Listen (false);
UDP_CloseSocket (net_controlsocket);
socExit();
}
//=============================================================================
void UDP_Listen (qboolean state)
{
// enable listening
if (state)
{
if (net_acceptsocket != -1)
return;
if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == -1)
Sys_Error ("UDP_Listen: Unable to open accept socket\n");
return;
}
// disable listening
if (net_acceptsocket == -1)
return;
UDP_CloseSocket (net_acceptsocket);
net_acceptsocket = -1;
}
//=============================================================================
int UDP_OpenSocket (int port)
{
int newsocket;
struct sockaddr_in address;
qboolean _true = true;
int yes = 1;
int rc;
if ((newsocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
return -1;
int flags = fcntl(newsocket, F_GETFL, 0);
if ( fcntl(newsocket, F_SETFL, flags | O_NONBLOCK) == -1)
goto ErrorReturn;
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(port);
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
goto ErrorReturn;
return newsocket;
ErrorReturn:
close (newsocket);
return -1;
}
//=============================================================================
int UDP_CloseSocket (int socket)
{
if (socket == net_broadcastsocket)
net_broadcastsocket = 0;
return close (socket);
}
//=============================================================================
/*
============
PartialIPAddress
this lets you type only as much of the net address as required, using
the local network components to fill in the rest
============
*/
static int PartialIPAddress (char *in, struct qsockaddr *hostaddr)
{
char buff[256];
char *b;
int addr;
int num;
int mask;
int run;
int port;
buff[0] = '.';
b = buff;
strcpy(buff+1, in);
if (buff[1] == '.')
b++;
addr = 0;
mask=-1;
while (*b == '.')
{
b++;
num = 0;
run = 0;
while (!( *b < '0' || *b > '9'))
{
num = num*10 + *b++ - '0';
if (++run > 3)
return -1;
}
if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
return -1;
if (num < 0 || num > 255)
return -1;
mask<<=8;
addr = (addr<<8) + num;
}
if (*b++ == ':')
port = Q_atoi(b);
else
port = net_hostport;
hostaddr->sa_family = AF_INET;
((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
return 0;
}
//=============================================================================
int UDP_Connect (int socket, struct qsockaddr *addr)
{
return 0;
}
//=============================================================================
int UDP_CheckNewConnections (void)
{
char buf[4096];
if (net_acceptsocket == -1)
return -1;
if (recvfrom(net_acceptsocket, buf, 4096, MSG_PEEK, NULL, NULL) > 0)
return net_acceptsocket;
return -1;
}
//=============================================================================
int UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr)
{
int addrlen = sizeof (struct qsockaddr);
int ret;
ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
if (ret == -1 )
return 0;
return ret;
}
//=============================================================================
int UDP_MakeSocketBroadcastCapable (int socket)
{
return -1;
}
//=============================================================================
int UDP_Broadcast (int socket, byte *buf, int len)
{
int ret;
if (socket != net_broadcastsocket)
{
if (net_broadcastsocket != 0)
Sys_Error("Attempted to use multiple broadcasts sockets\n");
ret = UDP_MakeSocketBroadcastCapable (socket);
if (ret == -1)
{
Con_Printf("Unable to make socket broadcast capable\n");
return ret;
}
}
return UDP_Write (socket, buf, len, &broadcastaddr);
}
//=============================================================================
int UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr)
{
int ret;
ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
if (ret == -1 )
return 0;
return ret;
}
//=============================================================================
char *UDP_AddrToString (struct qsockaddr *addr)
{
static char buffer[22];
int haddr;
haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
return buffer;
}
//=============================================================================
int UDP_StringToAddr (char *string, struct qsockaddr *addr)
{
int ha1, ha2, ha3, ha4, hp;
int ipaddr;
sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
addr->sa_family = AF_INET;
((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
((struct sockaddr_in *)addr)->sin_port = htons(hp);
return 0;
}
//=============================================================================
int UDP_GetSocketAddr (int socket, struct qsockaddr *addr)
{
int addrlen = sizeof(struct qsockaddr);
unsigned int a;
Q_memset(addr, 0, sizeof(struct qsockaddr));
getsockname(socket, (struct sockaddr *)addr, &addrlen);
a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
if (a == 0 || a == inet_addr("127.0.0.1"))
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
return 0;
}
//=============================================================================
int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name)
{
struct hostent *hostentry;
hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
if (hostentry)
{
Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
return 0;
}
Q_strcpy (name, UDP_AddrToString (addr));
return 0;
}
//=============================================================================
int UDP_GetAddrFromName(char *name, struct qsockaddr *addr)
{
struct hostent *hostentry;
if (name[0] >= '0' && name[0] <= '9')
return PartialIPAddress (name, addr);
hostentry = gethostbyname (name);
if (!hostentry)
return -1;
addr->sa_family = AF_INET;
((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);
((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
return 0;
}
//=============================================================================
int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
{
if (addr1->sa_family != addr2->sa_family)
return -1;
if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
return -1;
if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
return 1;
return 0;
}
//=============================================================================
int UDP_GetSocketPort (struct qsockaddr *addr)
{
return ntohs(((struct sockaddr_in *)addr)->sin_port);
}
int UDP_SetSocketPort (struct qsockaddr *addr, int port)
{
((struct sockaddr_in *)addr)->sin_port = htons(port);
return 0;
}
//=============================================================================

314
source/ctr/r_local.h Normal file
View file

@ -0,0 +1,314 @@
/*
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
#ifndef GLQUAKE
#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
typedef struct clipplane_s
{
vec3_t normal;
float dist;
struct clipplane_s *next;
byte leftedge;
byte rightedge;
byte 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_DrawSurfaceBlock16 (void);
void R_DrawSurfaceBlock8 (void);
texture_t *R_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];
#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
//=========================================================
#define MAXALIASVERTS 2000 // TODO: tune this
#define ALIAS_Z_CLIP_PLANE 5
extern int numverts;
extern int a_skinwidth;
extern mtriangle_t *ptriangles;
extern int numtriangles;
extern aliashdr_t *paliashdr;
extern mdl_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_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;
// 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 vrect_t *pconupdate;
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 R_TimeRefresh_f (void);
void R_TimeGraph (void);
void R_PrintAliasStats (void);
void R_PrintTimes (void);
void R_PrintDSpeeds (void);
void R_AnimateLight (void);
int R_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_SplitEntityOnNode2 (mnode_t *node);
void R_MarkLights (dlight_t *light, int bit, mnode_t *node);
#endif

851
source/ctr/r_part.c Normal file
View file

@ -0,0 +1,851 @@
/*
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.
*/
#include "../quakedef.h"
#define MAX_PARTICLES 2048 // default max # of particles at one
// time
#define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's
// on the command line
int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
particle_t *active_particles, *free_particles;
particle_t *particles;
int r_numparticles;
vec3_t r_pright, r_pup, r_ppn;
/*
===============
R_InitParticles
===============
*/
void R_InitParticles (void)
{
int i;
i = COM_CheckParm ("-particles");
if (i)
{
r_numparticles = (int)(Q_atoi(com_argv[i+1]));
if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
r_numparticles = ABSOLUTE_MIN_PARTICLES;
}
else
{
r_numparticles = MAX_PARTICLES;
}
particles = (particle_t *)
Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
QMB_InitParticles();
}
void R_DarkFieldParticles (entity_t *ent)
{
int i, j, k;
particle_t *p;
float vel;
vec3_t dir;
vec3_t org;
org[0] = ent->origin[0];
org[1] = ent->origin[1];
org[2] = ent->origin[2];
for (i=-16 ; i<16 ; i+=8)
for (j=-16 ; j<16 ; j+=8)
for (k=0 ; k<32 ; k+=8)
{
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 0.2 + (rand()&7) * 0.02;
p->color[0] = p->color[1] = p->color[2] = 150 + rand()%6;
p->type = pt_slowgrav;
dir[0] = j*8;
dir[1] = i*8;
dir[2] = k*8;
p->org[0] = org[0] + i + (rand()&3);
p->org[1] = org[1] + j + (rand()&3);
p->org[2] = org[2] + k + (rand()&3);
VectorNormalize (dir);
vel = 50 + (rand()&63);
VectorScale (dir, vel, p->vel);
}
}
/*
===============
R_EntityParticles
===============
*/
#define NUMVERTEXNORMALS 162
extern float r_avertexnormals[NUMVERTEXNORMALS][3];
vec3_t avelocities[NUMVERTEXNORMALS];
float beamlength = 16;
vec3_t avelocity = {23, 7, 3};
float partstep = 0.01;
float timescale = 0.01;
void R_EntityParticles (entity_t *ent)
{
int count;
int i;
particle_t *p;
float angle;
float sr, sp, sy, cr, cp, cy;
vec3_t forward;
float dist;
dist = 64;
count = 50;
if (!avelocities[0][0])
{
for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
avelocities[0][i] = (rand()&255) * 0.01;
}
for (i=0 ; i<NUMVERTEXNORMALS ; i++)
{
angle = cl.time * avelocities[i][0];
sy = sin(angle);
cy = cos(angle);
angle = cl.time * avelocities[i][1];
sp = sin(angle);
cp = cos(angle);
angle = cl.time * avelocities[i][2];
sr = sin(angle);
cr = cos(angle);
forward[0] = cp*cy;
forward[1] = cp*sy;
forward[2] = -sp;
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 0.01;
p->color[0] = p->color[1] = p->color[2] = 0x6f;
p->type = pt_explode;
p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;
p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;
p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;
}
}
/*
===============
R_ClearParticles
===============
*/
void R_Clear_Classic_Particles (void)
{
int i;
free_particles = &particles[0];
active_particles = NULL;
for (i=0 ;i<r_numparticles ; i++)
particles[i].next = &particles[i+1];
particles[r_numparticles-1].next = NULL;
}
void R_ClearParticles (void)
{
QMB_ClearParticles ();
R_Clear_Classic_Particles();
}
void R_ReadPointFile_f (void)
{
FILE *f;
vec3_t org;
int r;
int c;
particle_t *p;
char name[MAX_OSPATH];
sprintf (name,"maps/%s.pts", sv.name);
COM_FOpenFile (name, &f);
if (!f)
{
Con_Printf ("couldn't open %s\n", name);
return;
}
Con_Printf ("Reading %s...\n", name);
c = 0;
for ( ;; )
{
r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]);
if (r != 3)
break;
c++;
if (!free_particles)
{
Con_Printf ("Not enough free particles\n");
break;
}
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = 99999;
p->color[0] = p->color[1] = p->color[2] = (-c)&15;
p->type = pt_static;
VectorCopy (vec3_origin, p->vel);
VectorCopy (org, p->org);
}
fclose (f);
Con_Printf ("%i points read\n", c);
}
/*
===============
R_ParseParticleEffect
Parse an effect out of the server message
===============
*/
void R_ParseParticleEffect (void)
{
vec3_t org, dir;
int i, count, msgcount, color;
for (i=0 ; i<3 ; i++)
org[i] = MSG_ReadCoord ();
for (i=0 ; i<3 ; i++)
dir[i] = MSG_ReadChar () * (1.0/16);
msgcount = MSG_ReadByte ();
color = MSG_ReadByte ();
if (msgcount == 255)
count = 1024;
else
count = msgcount;
R_RunParticleEffect (org, dir, color, count);
}
/*
===============
R_ParticleExplosion
===============
*/
void R_ParticleExplosion (vec3_t org)
{
int i, j;
particle_t *p;
for (i=0 ; i<1024 ; i++)
{
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 5;
p->color[0] = p->color[1] = p->color[2] = ramp1[0];
p->ramp = rand()&3;
if (i & 1)
{
p->type = pt_explode;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
else
{
p->type = pt_explode2;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
}
}
/*
===============
R_ParticleExplosion2
===============
*/
void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
{
int i, j;
particle_t *p;
int colorMod = 0;
for (i=0; i<512; i++)
{
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 0.3;
p->color[0] = p->color[1] = p->color[2] = colorStart + (colorMod % colorLength);
colorMod++;
p->type = pt_blob;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
}
/*
===============
R_BlobExplosion
===============
*/
void R_BlobExplosion (vec3_t org)
{
int i, j;
particle_t *p;
for (i=0 ; i<1024 ; i++)
{
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 1 + (rand()&8)*0.05;
if (i & 1)
{
p->type = pt_blob;
p->color[0] = p->color[1] = p->color[2] = 66 + rand()%6;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
else
{
p->type = pt_blob2;
p->color[0] = p->color[1] = p->color[2] = 150 + rand()%6;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
}
}
/*
===============
R_RunParticleEffect
===============
*/
#define RunParticleEffect(org, dir, color, count) \
if (qmb_initialized) \
QMB_RunParticleEffect (org, dir, color, count); \
else \
Run_Classic_ParticleEffect (org, dir, color, count);
void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
{
if (color == 73 || color == 225)
{
RunParticleEffect(org, dir, color, count);
return;
}
switch (count)
{
case 10:
case 20:
case 30:
RunParticleEffect(org, dir, color, count);
break;
default:
RunParticleEffect(org, dir, color, count);
}
}
/*
===============
Run_Classic_ParticleEffect
===============
*/
void Run_Classic_ParticleEffect (vec3_t org, vec3_t dir, int color, int count)
{
int i, j;
particle_t *p;
for (i=0 ; i<count ; i++)
{
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
if (count == 1024)
{ // rocket explosion
p->die = cl.time + 5;
p->color[0] = p->color[1] = p->color[2] = ramp1[0];
p->ramp = rand()&3;
if (i & 1)
{
p->type = pt_explode;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
else
{
p->type = pt_explode2;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()%32)-16);
p->vel[j] = (rand()%512)-256;
}
}
}
else
{
p->die = cl.time + 0.1*(rand()%5);
p->color[0] = p->color[1] = p->color[2] = (color&~7) + (rand()&7);
p->type = pt_slowgrav;
for (j=0 ; j<3 ; j++)
{
p->org[j] = org[j] + ((rand()&15)-8);
p->vel[j] = dir[j]*15;// + (rand()%300)-150;
}
}
}
}
/*
===============
R_LavaSplash
===============
*/
void R_LavaSplash (vec3_t org)
{
int i, j, k;
particle_t *p;
float vel;
vec3_t dir;
for (i=-16 ; i<16 ; i++)
for (j=-16 ; j<16 ; j++)
for (k=0 ; k<1 ; k++)
{
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 2 + (rand()&31) * 0.02;
p->color[0] = p->color[1] = p->color[2] = 224 + (rand()&7);
p->type = pt_slowgrav;
dir[0] = j*8 + (rand()&7);
dir[1] = i*8 + (rand()&7);
dir[2] = 256;
p->org[0] = org[0] + dir[0];
p->org[1] = org[1] + dir[1];
p->org[2] = org[2] + (rand()&63);
VectorNormalize (dir);
vel = 50 + (rand()&63);
VectorScale (dir, vel, p->vel);
}
}
/*
===============
R_TeleportSplash
===============
*/
void R_TeleportSplash (vec3_t org)
{
int i, j, k;
particle_t *p;
float vel;
vec3_t dir;
for (i=-16 ; i<16 ; i+=4)
for (j=-16 ; j<16 ; j+=4)
for (k=-24 ; k<32 ; k+=4)
{
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
p->die = cl.time + 0.2 + (rand()&7) * 0.02;
p->color[0] = p->color[1] = p->color[2] = 7 + (rand()&7);
p->type = pt_slowgrav;
dir[0] = j*8;
dir[1] = i*8;
dir[2] = k*8;
p->org[0] = org[0] + i + (rand()&3);
p->org[1] = org[1] + j + (rand()&3);
p->org[2] = org[2] + k + (rand()&3);
VectorNormalize (dir);
vel = 50 + (rand()&63);
VectorScale (dir, vel, p->vel);
}
}
void R_RocketTrail (vec3_t start, vec3_t end, int type)
{
vec3_t vec;
float len;
int j;
particle_t *p;
int dec;
static int tracercount;
VectorSubtract (end, start, vec);
len = VectorNormalize (vec);
if (type < 128)
dec = 3;
else
{
dec = 1;
type -= 128;
}
while (len > 0)
{
len -= dec;
if (!free_particles)
return;
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
VectorCopy (vec3_origin, p->vel);
p->die = cl.time + 2;
switch (type)
{
case 0: // rocket trail
p->ramp = (rand()&3);
p->color[0] = p->color[1] = p->color[2] = ramp3[(int)p->ramp];
p->type = pt_fire;
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()%6)-3);
break;
case 1: // smoke smoke
p->ramp = (rand()&3) + 2;
p->color[0] = p->color[1] = p->color[2] = ramp3[(int)p->ramp];
p->type = pt_fire;
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()%6)-3);
break;
case 2: // blood
p->type = pt_grav;
p->color[0] = p->color[1] = p->color[2] = 67 + (rand()&3);
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()%6)-3);
break;
case 3:
case 5: // tracer
p->die = cl.time + 0.5;
p->type = pt_static;
if (type == 3)
p->color[0] = p->color[1] = p->color[2] = 52 + ((tracercount&4)<<1);
else
p->color[0] = p->color[1] = p->color[2] = 230 + ((tracercount&4)<<1);
tracercount++;
VectorCopy (start, p->org);
if (tracercount & 1)
{
p->vel[0] = 30*vec[1];
p->vel[1] = 30*-vec[0];
}
else
{
p->vel[0] = 30*-vec[1];
p->vel[1] = 30*vec[0];
}
break;
case 4: // slight blood
p->type = pt_grav;
p->color[0] = p->color[1] = p->color[2] = 67 + (rand()&3);
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()%6)-3);
len -= 3;
break;
case 6: // voor trail
p->color[0] = p->color[1] = p->color[2] = 9*16 + 8 + (rand()&3);
p->type = pt_static;
p->die = cl.time + 0.3;
for (j=0 ; j<3 ; j++)
p->org[j] = start[j] + ((rand()&15)-8);
break;
}
VectorAdd (start, vec, start);
}
}
/*
===============
R_Classic_DrawParticles
===============
*/
extern cvar_t sv_gravity;
void R_Classic_DrawParticles (void)
{
particle_t *p, *kill;
float grav;
int i;
float time2, time3;
float time1;
float dvel;
float frametime;
#ifdef GLQUAKE
vec3_t up, right;
float scale;
GL_Bind(particletexture);
glEnable (GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBegin (GL_TRIANGLES);
VectorScale (vup, 1.5, up);
VectorScale (vright, 1.5, right);
#else
D_StartParticles ();
VectorScale (vright, xscaleshrink, r_pright);
VectorScale (vup, yscaleshrink, r_pup);
VectorCopy (vpn, r_ppn);
#endif
frametime = cl.time - cl.oldtime;
time3 = frametime * 15;
time2 = frametime * 10; // 15;
time1 = frametime * 5;
grav = frametime * sv_gravity.value * 0.05;
dvel = 4*frametime;
for ( ;; )
{
kill = active_particles;
if (kill && kill->die < cl.time)
{
active_particles = kill->next;
kill->next = free_particles;
free_particles = kill;
continue;
}
break;
}
for (p=active_particles ; p ; p=p->next)
{
for ( ;; )
{
kill = p->next;
if (kill && kill->die < cl.time)
{
p->next = kill->next;
kill->next = free_particles;
free_particles = kill;
continue;
}
break;
}
#ifdef GLQUAKE
// hack a scale up to keep particles from disapearing
scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
+ (p->org[2] - r_origin[2])*vpn[2];
if (scale < 20)
scale = 1;
else
scale = 1 + scale * 0.004;
glColor4ubv (p->color);
glTexCoord2f (0,0);
glVertex3fv (p->org);
glTexCoord2f (1,0);
glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
glTexCoord2f (0,1);
glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
#else
D_DrawParticle (p);
#endif
p->org[0] += p->vel[0]*frametime;
p->org[1] += p->vel[1]*frametime;
p->org[2] += p->vel[2]*frametime;
switch (p->type)
{
case pt_static:
break;
case pt_fire:
p->ramp += time1;
if (p->ramp >= 6)
p->die = -1;
else
p->color[0] = p->color[1] = p->color[2] = ramp3[(int)p->ramp];
p->vel[2] += grav;
break;
case pt_explode:
p->ramp += time2;
if (p->ramp >=8)
p->die = -1;
else
p->color[0] = p->color[1] = p->color[2] = ramp1[(int)p->ramp];
for (i=0 ; i<3 ; i++)
p->vel[i] += p->vel[i]*dvel;
p->vel[2] -= grav;
break;
case pt_explode2:
p->ramp += time3;
if (p->ramp >=8)
p->die = -1;
else
p->color[0] = p->color[1] = p->color[2] = ramp2[(int)p->ramp];
for (i=0 ; i<3 ; i++)
p->vel[i] -= p->vel[i]*frametime;
p->vel[2] -= grav;
break;
case pt_blob:
for (i=0 ; i<3 ; i++)
p->vel[i] += p->vel[i]*dvel;
p->vel[2] -= grav;
break;
case pt_blob2:
for (i=0 ; i<2 ; i++)
p->vel[i] -= p->vel[i]*dvel;
p->vel[2] -= grav;
break;
case pt_grav:
#ifdef QUAKE2
p->vel[2] -= grav * 20;
break;
#endif
case pt_slowgrav:
p->vel[2] -= grav;
break;
}
}
#ifdef GLQUAKE
glEnd ();
glDisable (GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
#else
D_EndParticles ();
#endif
}
/*
===============
R_DrawParticles
===============
*/
void R_DrawParticles (void)
{
R_Classic_DrawParticles ();
QMB_DrawParticles ();
}

155
source/ctr/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.
*/
#ifndef GLQUAKE
// 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 MAXDIMENSION ((MAXHEIGHT > MAXWIDTH) ? MAXHEIGHT : MAXWIDTH)
#define SIN_BUFFER_SIZE (MAXDIMENSION+CYCLE)
#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 pixel_t *cacheblock;
extern int screenwidth;
extern float pixelAspect;
extern int r_drawnpolycount;
extern cvar_t r_clearcolor;
extern int sintable[SIN_BUFFER_SIZE];
extern int intsintable[SIN_BUFFER_SIZE];
extern vec3_t vup, base_vup;
extern vec3_t vpn, base_vpn;
extern vec3_t vright, base_vright;
extern entity_t *currententity;
#define NUMSTACKEDGES 2400
#define MINEDGES NUMSTACKEDGES
#define NUMSTACKSURFACES 800
#define MINSURFACES NUMSTACKSURFACES
#define MAXSPANS 3000
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
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 // GLQUAKE

199
source/ctr/render.h Normal file
View file

@ -0,0 +1,199 @@
/*
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.
*/
// refresh.h -- public interface to refresh functions
#define MAXCLIPPLANES 11
#define TOP_RANGE 16 // soldier uniform colors
#define BOTTOM_RANGE 96
//=============================================================================
typedef struct efrag_s
{
struct mleaf_s *leaf;
struct efrag_s *leafnext;
struct entity_s *entity;
struct efrag_s *entnext;
} efrag_t;
typedef struct entity_s
{
qboolean forcelink; // model changed
int update_type;
entity_state_t baseline; // to fill in defaults in updates
double msgtime; // time of last update
vec3_t msg_origins[2]; // last two updates (0 is newest)
vec3_t origin;
vec3_t msg_angles[2]; // last two updates (0 is newest)
vec3_t angles;
// Tomaz - QC Alpha Scale Glow Begin
float renderamt;
float rendermode;
float rendercolor[3];
//Crow_bar
unsigned char scale;
struct model_s *model; // NULL = no model
char old_model[128]; // NULL = no model
struct efrag_s *efrag; // linked list of efrags
int frame;
float syncbase; // for client-side animations
byte *colormap;
int effects; // light, particals, etc
int skinnum; // for Alias models
int visframe; // last frame this entity was
// found in an active leaf
// fenix@io.com: model transform interpolation
float translate_start_time;
vec3_t origin1;
vec3_t origin2;
float rotate_start_time;
vec3_t angles1;
vec3_t angles2;
int dlightframe; // dynamic lighting
int dlightbits;
// FIXME: could turn these into a union
int trivial_accept;
struct mnode_s *topnode; // for bmodels, first world node
// that splits bmodel, or NULL if
// not split
float frame_start_time;
float frame_interval;
int pose1;
int pose2;
int modelindex;
int z_head;
int z_larm;
int z_rarm;
} entity_t;
typedef struct
{
vrect_t vrect; // subwindow in video for refresh
// FIXME: not need vrect next field here?
vrect_t aliasvrect; // scaled Alias version
int vrectright, vrectbottom; // right & bottom screen coords
int aliasvrectright, aliasvrectbottom; // scaled Alias versions
float vrectrightedge; // rightmost right edge we care about,
// for use in edge list
float fvrectx, fvrecty; // for floating-point compares
float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping
int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20
int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20
float fvrectright_adj, fvrectbottom_adj;
// right and bottom edges, for clamping
float fvrectright; // rightmost edge, for Alias clamping
float fvrectbottom; // bottommost edge, for Alias clamping
float horizontalFieldOfView; // at Z = 1.0, this many X is visible
// 2.0 = 90 degrees
float xOrigin; // should probably allways be 0.5
float yOrigin; // between be around 0.3 to 0.5
vec3_t vieworg;
vec3_t viewangles;
float fov_x, fov_y;
int ambientlight;
float fog_start;
float fog_end;
float fog_red;
float fog_green;
float fog_blue;
} refdef_t;
//
// refresh
//
extern int reinit_surfcache;
extern refdef_t r_refdef;
extern vec3_t r_origin, vpn, vright, vup;
extern struct texture_s *r_notexture_mip;
void R_Init (void);
void R_InitTextures (void);
void R_InitEfrags (void);
void R_RenderView (void); // must set r_refdef first
void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect);
// called whenever r_refdef or vid change
void R_InitSky (struct miptex_s *mt); // called at level load
void R_AddEfrags (entity_t *ent);
void R_RemoveEfrags (entity_t *ent);
void R_NewMap (void);
// particles
typedef enum trail_type_s
{
ROCKET_TRAIL, GRENADE_TRAIL, BLOOD_TRAIL, TRACER1_TRAIL, SLIGHT_BLOOD_TRAIL,NAIL_TRAIL,
TRACER2_TRAIL, VOOR_TRAIL, ALT_ROCKET_TRAIL, LAVA_TRAIL, BUBBLE_TRAIL, NEHAHRA_SMOKE,
RAYGREEN_TRAIL, RAYRED_TRAIL
} trail_type_t;
void R_ParseParticleEffect (void);
void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);
void R_RocketTrail (vec3_t start, vec3_t end, int type);
#ifdef QUAKE2
void R_DarkFieldParticles (entity_t *ent);
#endif
void R_EntityParticles (entity_t *ent);
void R_BlobExplosion (vec3_t org);
void R_ParticleExplosion (vec3_t org);
void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength);
void R_LavaSplash (vec3_t org);
void R_TeleportSplash (vec3_t org);
void R_PushDlights (void);
//
// surface cache related
//
extern int reinit_surfcache; // if 1, surface cache is currently empty and
extern qboolean r_cache_thrash; // set if thrashing the surface cache
int D_SurfaceCacheForRes (int width, int height);
void D_FlushCaches (void);
void D_DeleteSurfaceCache (void);
void D_InitCaches (void *buffer, int size);
void R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj);

335
source/ctr/sbar.c Normal file
View file

@ -0,0 +1,335 @@
/*
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.
*/
// sbar.c -- status bar code
#include "../quakedef.h"
int sb_updates; // if >= vid.numpages, no update needed
#define STAT_MINUS 10 // num frame for '-' stats digit
qpic_t *sb_nums[2][11];
qpic_t *sb_colon, *sb_slash;
qpic_t *sb_ibar;
qpic_t *sb_sbar;
qpic_t *sb_scorebar;
qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes
qpic_t *sb_ammo[4];
qpic_t *sb_sigil[4];
qpic_t *sb_armor[3];
qpic_t *sb_items[32];
qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive
// 0 is static, 1 is temporary animation
qpic_t *sb_face_invis;
qpic_t *sb_face_quad;
qpic_t *sb_face_invuln;
qpic_t *sb_face_invis_invuln;
extern qboolean sb_showscores;
extern int sb_lines; // scan lines to draw
qpic_t *rsb_invbar[2];
qpic_t *rsb_weapons[5];
qpic_t *rsb_items[2];
qpic_t *rsb_ammo[3];
qpic_t *rsb_teambord; // PGM 01/19/97 - team color border
//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
qpic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
//MED 01/04/97 added array to simplify weapon parsing
//int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
//MED 01/04/97 added hipnotic items array
qpic_t *hsb_items[2];
void Sbar_MiniDeathmatchOverlay (void);
void Sbar_DeathmatchOverlay (void);
void M_DrawPic (int x, int y, qpic_t *pic);
/*
===============
Sbar_ShowScores
Tab key down
===============
*/
void Sbar_ShowScores (void)
{
}
/*
===============
Sbar_DontShowScores
Tab key up
===============
*/
void Sbar_DontShowScores (void)
{
}
/*
===============
Sbar_Changed
===============
*/
void Sbar_Changed (void)
{
}
/*
===============
Sbar_Init
===============
*/
void Sbar_Init (void)
{
}
//=============================================================================
// drawing routines are relative to the status bar location
/*
=============
Sbar_DrawPic
=============
*/
void Sbar_DrawPic (int x, int y, qpic_t *pic)
{
}
/*
=============
Sbar_DrawTransPic
=============
*/
void Sbar_DrawTransPic (int x, int y, qpic_t *pic)
{
}
/*
================
Sbar_DrawCharacter
Draws one solid graphics character
================
*/
void Sbar_DrawCharacter (int x, int y, int num)
{
}
/*
================
Sbar_DrawString
================
*/
void Sbar_DrawString (int x, int y, char *str)
{
}
/*
=============
Sbar_itoa
=============
*/
int Sbar_itoa (int num, char *buf)
{
}
/*
=============
Sbar_DrawNum
=============
*/
void Sbar_DrawNum (int x, int y, int num, int digits, int color)
{
}
//=============================================================================
int fragsort[MAX_SCOREBOARD];
/*
===============
Sbar_SortFrags
===============
*/
void Sbar_SortFrags (void)
{
}
int Sbar_ColorForMap (int m)
{
return m < 128 ? m + 8 : m + 8;
}
/*
===============
Sbar_UpdateScoreboard
===============
*/
void Sbar_UpdateScoreboard (void)
{
}
/*
===============
Sbar_SoloScoreboard
===============
*/
void Sbar_SoloScoreboard (void)
{
}
/*
===============
Sbar_DrawScoreboard
===============
*/
void Sbar_DrawScoreboard (void)
{
}
//=============================================================================
/*
===============
Sbar_DrawInventory
===============
*/
void Sbar_DrawInventory (void)
{
}
//=============================================================================
/*
===============
Sbar_DrawFrags
===============
*/
void Sbar_DrawFrags (void)
{
}
//=============================================================================
/*
===============
Sbar_DrawFace
===============
*/
void Sbar_DrawFace (void)
{
}
/*
===============
Sbar_Draw
===============
*/
void Sbar_Draw (void)
{
}
//=============================================================================
/*
==================
Sbar_IntermissionNumber
==================
*/
void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
{
}
/*
==================
Sbar_DeathmatchOverlay
==================
*/
void Sbar_DeathmatchOverlay (void)
{
}
/*
==================
Sbar_DeathmatchOverlay
==================
*/
void Sbar_MiniDeathmatchOverlay (void)
{
}
/*
==================
Sbar_IntermissionOverlay
==================
*/
void Sbar_IntermissionOverlay (void)
{
}
/*
==================
Sbar_FinaleOverlay
==================
*/
void Sbar_FinaleOverlay (void)
{
}

39
source/ctr/sbar.h 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.
*/
// the status bar is only redrawn if something has changed, but if anything
// does, the entire thing will be redrawn for the next vid.numpages frames.
#define SBAR_HEIGHT 24
extern int sb_lines; // scan lines to draw
void Sbar_Init (void);
void Sbar_Changed (void);
// call whenever any of the client stats represented on the sbar changes
void Sbar_Draw (void);
// called every frame by screen
void Sbar_IntermissionOverlay (void);
// called each frame after the level has been completed
void Sbar_FinaleOverlay (void);

62
source/ctr/screen.h 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.
*/
// screen.h
void SCR_Init (void);
void SCR_UpdateScreen (void);
void SCR_SizeUp (void);
void SCR_SizeDown (void);
void SCR_BringDownConsole (void);
void SCR_CenterPrint (char *str);
void SCR_UsePrint (int type, int cost, int weapon);
qpic_t *GetButtonIcon (char *buttonname);
char *GetGrenadeButtonL();
void SCR_BeginLoadingPlaque (void);
void SCR_EndLoadingPlaque (void);
int SCR_ModalMessage (char *text);
extern float scr_con_current;
extern float scr_conlines; // lines of console to display
extern int scr_fullupdate; // set to 0 to force full redraw
extern int sb_lines;
extern int clearnotify; // set to 0 whenever notify text is drawn
extern qboolean scr_disabled_for_loading;
extern qboolean scr_skipupdate;
extern cvar_t scr_viewsize;
extern cvar_t scr_viewsize;
// only the refresh window will be updated unless these variables are flagged
extern int scr_copytop;
extern int scr_copyeverything;
extern qboolean block_drawing;
void SCR_UpdateWholeScreen (void);
extern cvar_t scr_fov;

267
source/ctr/server.h Normal file
View file

@ -0,0 +1,267 @@
/*
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.
*/
// server.h
typedef struct
{
int maxclients;
int maxclientslimit;
struct client_s *clients; // [maxclients]
int serverflags; // episode completion information
qboolean changelevel_issued; // cleared when at SV_SpawnServer
} server_static_t;
//=============================================================================
typedef enum {ss_loading, ss_active} server_state_t;
typedef struct
{
qboolean active; // false if only a net client
qboolean paused;
qboolean loadgame; // handle connections specially
double time;
int lastcheck; // used by PF_checkclient
double lastchecktime;
char name[64]; // map name
#ifdef QUAKE2
char startspot[64];
#endif
char modelname[64]; // maps/<name>.bsp, for model_precache[0]
struct model_s *worldmodel;
char *model_precache[MAX_MODELS]; // NULL terminated
struct model_s *models[MAX_MODELS];
char *sound_precache[MAX_SOUNDS]; // NULL terminated
char *lightstyles[MAX_LIGHTSTYLES];
int num_edicts;
int max_edicts;
edict_t *edicts; // can NOT be array indexed, because
// edict_t is variable sized, but can
// be used to reference the world ent
server_state_t state; // some actions are only valid during load
sizebuf_t datagram;
byte datagram_buf[MAX_DATAGRAM];
sizebuf_t reliable_datagram; // copied to all clients at end of frame
byte reliable_datagram_buf[MAX_DATAGRAM];
sizebuf_t signon;
byte signon_buf[8192];
} server_t;
#define NUM_PING_TIMES 16
#define NUM_SPAWN_PARMS 16
typedef struct client_s
{
qboolean active; // false = client is free
qboolean spawned; // false = don't send datagrams
qboolean dropasap; // has been told to go to another level
qboolean privileged; // can execute any host command
qboolean sendsignon; // only valid before spawned
double last_message; // reliable messages must be sent
// periodically
struct qsocket_s *netconnection; // communications handle
usercmd_t cmd; // movement
vec3_t wishdir; // intended motion calced from cmd
sizebuf_t message; // can be added to at any time,
// copied and clear once per frame
byte msgbuf[MAX_MSGLEN];
edict_t *edict; // EDICT_NUM(clientnum+1)
char name[32]; // for printing to other people
int colors;
float ping_times[NUM_PING_TIMES];
int num_pings; // ping_times[num_pings%NUM_PING_TIMES]
// spawn parms are carried from level to level
float spawn_parms[NUM_SPAWN_PARMS];
// client known data for deltas
//int old_frags;
int old_points;
int old_kills;
// joe, from ProQuake: allow clients to connect if they don't have the map
qboolean nomap;
} client_t;
//=============================================================================
// edict->movetype values
#define MOVETYPE_NONE 0 // never moves
#define MOVETYPE_ANGLENOCLIP 1
#define MOVETYPE_ANGLECLIP 2
#define MOVETYPE_WALK 3 // gravity
#define MOVETYPE_STEP 4 // gravity, special edge handling
#define MOVETYPE_FLY 5
#define MOVETYPE_TOSS 6 // gravity
#define MOVETYPE_PUSH 7 // no clip to world, push and crush
#define MOVETYPE_NOCLIP 8
#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
#define MOVETYPE_BOUNCE 10
#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity
#define MOVETYPE_FOLLOW 12 // track movement of aiment
// edict->solid values
#define SOLID_NOT 0 // no interaction with other objects
#define SOLID_TRIGGER 1 // touch on edge, but not blocking
#define SOLID_BBOX 2 // touch on edge, block
#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
#define SOLID_BSP 4 // bsp clip, touch on edge, block
#define SOLID_CORPSE 5 // bsp clip, touch on edge, block
// edict->deadflag values
#define DEAD_NO 0
#define DEAD_DYING 1
#define DEAD_DEAD 2
#define DAMAGE_NO 0
#define DAMAGE_YES 1
#define DAMAGE_AIM 2
// edict->flags
#define FL_FLY 1
#define FL_SWIM 2
//#define FL_GLIMPSE 4
#define FL_CONVEYOR 4
#define FL_CLIENT 8
#define FL_INWATER 16
#define FL_MONSTER 32
#define FL_GODMODE 64
#define FL_NOTARGET 128
#define FL_ITEM 256
#define FL_ONGROUND 512
#define FL_PARTIALGROUND 1024 // not all corners are valid
#define FL_WATERJUMP 2048 // player jumping out of water
#define FL_JUMPRELEASED 4096 // for jump debouncing
#ifdef QUAKE2
#define FL_FLASHLIGHT 8192
#define FL_ARCHIVE_OVERRIDE 1048576
#endif
// entity effects
#define EF_BLUELIGHT 1
#define EF_MUZZLEFLASH 2
#define EF_BRIGHTLIGHT 4
#define EF_REDLIGHT 8
#define EF_ORANGELIGHT 16
#define EF_GREENLIGHT 32
#define EF_PINKLIGHT 64 // formerly EF_LIGHT
#define EF_NODRAW 128
#define EF_LIMELIGHT 256 // formerly EF_BRIGHTFIELD
#define EF_FULLBRIGHT 512
#define EF_CYANLIGHT 1024 // formerly EF_DARKLIGHT
#define EF_YELLOWLIGHT 2048 // formerly EF_DARKFIELD
#define EF_PURPLELIGHT 4096
#define EF_RAYRED 8196 // red trail for porter x2
#define EF_RAYGREEN 16384 // green trail for ray gun
#define SPAWNFLAG_NOT_EASY 256
#define SPAWNFLAG_NOT_MEDIUM 512
#define SPAWNFLAG_NOT_HARD 1024
#define SPAWNFLAG_NOT_DEATHMATCH 2048
#ifdef QUAKE2
// server flags
#define SFL_EPISODE_1 1
#define SFL_EPISODE_2 2
#define SFL_EPISODE_3 4
#define SFL_EPISODE_4 8
#define SFL_NEW_UNIT 16
#define SFL_NEW_EPISODE 32
#define SFL_CROSS_TRIGGERS 65280
#endif
//============================================================================
extern cvar_t teamplay;
extern cvar_t skill;
extern cvar_t deathmatch;
extern cvar_t coop;
extern cvar_t fraglimit;
extern cvar_t timelimit;
extern server_static_t svs; // persistant server info
extern server_t sv; // local server
extern client_t *host_client;
extern jmp_buf host_abortserver;
extern double host_time;
extern edict_t *sv_player;
//===========================================================
void SV_Init (void);
void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count);
void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,
float attenuation);
void SV_DropClient (qboolean crash);
void SV_SendClientMessages (void);
void SV_ClearDatagram (void);
int SV_ModelIndex (char *name);
void SV_SetIdealPitch (void);
void SV_AddUpdates (void);
void SV_ClientThink (void);
void SV_AddClientToServer (struct qsocket_s *ret);
void SV_ClientPrintf (char *fmt, ...);
void SV_BroadcastPrintf (char *fmt, ...);
void SV_Physics (void);
qboolean SV_CheckBottom (edict_t *ent);
qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink);
void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg);
void SV_MoveToGoal (void);
void SV_MoveToOrigin (void);
void SV_CheckForNewClients (void);
void SV_RunClients (void);
void SV_SaveSpawnparms ();
#ifdef QUAKE2
void SV_SpawnServer (char *server, char *startspot);
#else
void SV_SpawnServer (char *server);
#endif

97
source/ctr/snd_ctr.c Normal file
View file

@ -0,0 +1,97 @@
/*
Copyright (C) 2017 Felipe Izzo
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.
*/
#include <stdio.h>
#include <3ds.h>
#include "../quakedef.h"
#define SAMPLE_RATE 22050
#define NUM_SAMPLES 2048
#define SAMPLE_SIZE 4
#define BUFFER_SIZE NUM_SAMPLES*SAMPLE_SIZE
static int sound_initialized = 0;
static byte *audio_buffer;
static ndspWaveBuf wave_buf;
qboolean SNDDMA_Init(void)
{
sound_initialized = 0;
if(ndspInit() != 0) {
return false;
}
audio_buffer = linearAlloc(BUFFER_SIZE);
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
ndspChnReset(0);
ndspChnWaveBufClear(0);
ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
ndspChnSetRate(0, (float)SAMPLE_RATE);
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
memset(&wave_buf, 0, sizeof(wave_buf));
wave_buf.data_vaddr = audio_buffer;
wave_buf.nsamples = BUFFER_SIZE / 4;
wave_buf.looping = 1;
shm = &sn;
shm->splitbuffer = 0;
shm->samplebits = 16;
shm->speed = SAMPLE_RATE;
shm->channels = 2;
shm->samples = BUFFER_SIZE / 2;
shm->samplepos = 0;
shm->submission_chunk = 1;
shm->buffer = audio_buffer;
ndspChnWaveBufAdd(0, &wave_buf);
sound_initialized = 1;
return true;
}
int SNDDMA_GetDMAPos(void)
{
if(!sound_initialized)
return 0;
shm->samplepos = ndspChnGetSamplePos(0) / (shm->samplebits / 8);
return shm->samplepos;
}
void SNDDMA_Shutdown(void)
{
if(!sound_initialized)
return;
ndspChnWaveBufClear(0);
ndspExit();
linearFree(audio_buffer);
sound_initialized = 0;
}
void SNDDMA_Submit(void)
{
}

10
source/ctr/strl_fn.h Normal file
View file

@ -0,0 +1,10 @@
/* header file for BSD strlcat and strlcpy */
#ifndef __STRLFUNCS_H
#define __STRLFUNCS_H
/* use our own copies of strlcpy and strlcat taken from OpenBSD */
extern size_t q_strlcpy (char *dst, const char *src, size_t size);
extern size_t q_strlcat (char *dst, const char *src, size_t size);
#endif /* __STRLFUNCS_H */

71
source/ctr/sys.h Normal file
View file

@ -0,0 +1,71 @@
/*
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.
*/
// sys.h -- non-portable functions
//
// file IO
//
// returns the file size
// return -1 if file is not present
// the file should be in BINARY mode for stupid OSs that care
int Sys_FileOpenRead (char *path, int *hndl);
int Sys_FileOpenWrite (char *path);
void Sys_FileClose (int handle);
void Sys_FileSeek (int handle, int position);
int Sys_FileRead (int handle, void *dest, int count);
int Sys_FileWrite (int handle, void *data, int count);
int Sys_FileTime (char *path);
void Sys_mkdir (char *path);
//
// memory protection
//
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
//
// system IO
//
void Sys_DebugLog(char *file, char *fmt, ...);
void Sys_Error (char *error, ...);
// an error will cause the entire program to exit
void Sys_Printf (char *fmt, ...);
// send text to the console
void Sys_Quit (void);
double Sys_FloatTime (void);
char *Sys_ConsoleInput (void);
void Sys_Sleep (void);
// called to yield for a little bit so as
// not to hog cpu when paused or debugging
void Sys_SendKeyEvents (void);
// Perform Key_Event () callbacks until the input que is empty
void Sys_LowFPPrecision (void);
void Sys_HighFPPrecision (void);
void Sys_SetFPCW (void);

340
source/ctr/sys_ctr.c Normal file
View file

@ -0,0 +1,340 @@
/*
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.
*/
#include "../quakedef.h"
#include "errno.h"
#include "touch_ctr.h"
#include <3ds.h>
#define TICKS_PER_SEC 268123480.0
int __stacksize__ = 4 * 1024 * 1024;
u32 __ctru_linear_heap_size = 28 * 1024 * 1024;
bool new3ds_flag;
extern void Touch_Init();
extern void Touch_Update();
qboolean isDedicated;
/*
===============================================================================
FILE IO
===============================================================================
*/
#define MAX_HANDLES 10
FILE *sys_handles[MAX_HANDLES];
int findhandle (void)
{
int i;
for (i=1 ; i<MAX_HANDLES ; i++)
if (!sys_handles[i])
return i;
Sys_Error ("out of handles");
return -1;
}
/*
================
filelength
================
*/
int filelength (FILE *f)
{
int pos;
int end;
pos = ftell (f);
fseek (f, 0, SEEK_END);
end = ftell (f);
fseek (f, pos, SEEK_SET);
return end;
}
int Sys_FileOpenRead (char *path, int *hndl)
{
FILE *f;
int i;
i = findhandle ();
f = fopen(path, "rb");
if (!f)
{
*hndl = -1;
return -1;
}
sys_handles[i] = f;
*hndl = i;
return filelength(f);
}
int Sys_FileOpenWrite (char *path)
{
FILE *f;
int i;
i = findhandle ();
f = fopen(path, "wb");
if (!f)
Sys_Error ("Error opening %s: %s", path,strerror(errno));
sys_handles[i] = f;
return i;
}
void Sys_FileClose (int handle)
{
fclose (sys_handles[handle]);
sys_handles[handle] = NULL;
}
void Sys_FileSeek (int handle, int position)
{
fseek (sys_handles[handle], position, SEEK_SET);
}
int Sys_FileRead (int handle, void *dest, int count)
{
return fread (dest, 1, count, sys_handles[handle]);
}
int Sys_FileWrite (int handle, void *data, int count)
{
return fwrite (data, 1, count, sys_handles[handle]);
}
int Sys_FileTime (char *path)
{
FILE *f;
f = fopen(path, "rb");
if (f)
{
fclose(f);
return 1;
}
return -1;
}
void Sys_mkdir (char *path)
{
mkdir(path, 0777);
}
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
{
}
void Sys_Error (char *error, ...)
{
consoleInit(GFX_BOTTOM, NULL);
va_list argptr;
printf ("Sys_Error: ");
va_start (argptr,error);
vprintf (error,argptr);
va_end (argptr);
printf ("\n");
while(!(hidKeysDown() & KEY_START))
hidScanInput();
Host_Shutdown();
gfxExit();
Sys_Quit();
}
void Sys_Printf (char *fmt, ...)
{
va_list argptr;
va_start (argptr,fmt);
vprintf (fmt,argptr);
va_end (argptr);
}
void Sys_Quit (void)
{
Host_Shutdown();
gfxExit();
exit(0);
}
double Sys_FloatTime (void)
{
static u64 initial_tick = 0;
if(!initial_tick)
initial_tick = svcGetSystemTick();
u64 current_tick = svcGetSystemTick();
return (current_tick - initial_tick)/TICKS_PER_SEC;
}
char *Sys_ConsoleInput (void)
{
return NULL;
}
void Sys_Sleep (void)
{
}
void Sys_DefaultConfig(void)
{
// naievil -- fixme I didn't do this
Cbuf_AddText ("bind ABUTTON +right\n");
Cbuf_AddText ("bind BBUTTON +lookdown\n");
Cbuf_AddText ("bind XBUTTON +lookup\n");
Cbuf_AddText ("bind YBUTTON +left\n");
Cbuf_AddText ("bind LTRIGGER +jump\n");
Cbuf_AddText ("bind RTRIGGER +attack\n");
Cbuf_AddText ("bind PADUP \"impulse 10\"\n");
Cbuf_AddText ("bind PADDOWN \"impulse 12\"\n");
//Cbuf_AddText ("lookstrafe \"1.000000\"\n");
//Cbuf_AddText ("lookspring \"0.000000\"\n");
}
void Sys_SetKeys(u32 keys, u32 state){
if( keys & KEY_SELECT)
Key_Event(K_SELECT, state);
if( keys & KEY_START)
Key_Event(K_ESCAPE, state);
if( keys & KEY_DUP)
Key_Event(K_UPARROW, state);
if( keys & KEY_DDOWN)
Key_Event(K_DOWNARROW, state);
if( keys & KEY_DLEFT)
Key_Event(K_LEFTARROW, state);
if( keys & KEY_DRIGHT)
Key_Event(K_RIGHTARROW, state);
if( keys & KEY_Y)
Key_Event(K_AUX4, state);
if( keys & KEY_X)
Key_Event(K_AUX3, state);
if( keys & KEY_B)
Key_Event(K_AUX2, state);
if( keys & KEY_A)
Key_Event(K_AUX1, state);
if( keys & KEY_L)
Key_Event(K_AUX5, state);
if( keys & KEY_R)
Key_Event(K_AUX7, state);
if( keys & KEY_ZL)
Key_Event(K_AUX6, state);
if( keys & KEY_ZR)
Key_Event(K_AUX8, state);
}
void Sys_SendKeyEvents (void)
{
hidScanInput();
u32 kDown = hidKeysDown();
u32 kUp = hidKeysUp();
if(kDown)
Sys_SetKeys(kDown, true);
if(kUp)
Sys_SetKeys(kUp, false);
Touch_Update();
}
void Sys_HighFPPrecision (void)
{
}
void Sys_LowFPPrecision (void)
{
}
//=============================================================================
bool game_running;
int main (int argc, char **argv)
{
static float time, oldtime;
static quakeparms_t parms;
new3ds_flag = false;
osSetSpeedupEnable(true);
APT_CheckNew3DS(&new3ds_flag);
gfxInit(GSP_BGR8_OES, GSP_RGB565_OES, false);
gfxSetDoubleBuffering(GFX_BOTTOM, false);
gfxSwapBuffersGpu();
uint8_t model;
cfguInit();
CFGU_GetSystemModel(&model);
cfguExit();
if(model != CFG_MODEL_2DS && new3ds_flag == true)
gfxSetWide(true);
chdir("sdmc:/3ds/nzportable");
if (new3ds_flag == true)
parms.memsize = 64 * 1024 * 1024;
else
parms.memsize = 16 * 1024 * 1024;
parms.membase = malloc (parms.memsize);
parms.basedir = ".";
COM_InitArgv (argc, argv);
parms.argc = com_argc;
parms.argv = com_argv;
Host_Init (&parms);
Touch_Init();
Touch_DrawOverlay();
oldtime = Sys_FloatTime();
game_running = true;
while (aptMainLoop() && game_running)
{
time = Sys_FloatTime();
Host_Frame (time - oldtime);
oldtime = time;
}
return 0;
}

92
source/ctr/touch_ctr.c Normal file
View file

@ -0,0 +1,92 @@
/*
Copyright (C) 2015 Felipe Izzo
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.
*/
//FIX ME: load all hardcoded values from file
#include "../quakedef.h"
#include <3ds.h>
#include "touch_ctr.h"
u16* touchOverlay;
char lastKey = 0;
int tmode;
u16* tfb;
touchPosition oldtouch, touch;
u64 tick;
u64 lastTap = 0;
int shiftToggle = 0;
void Touch_Init(){
tmode = TMODE_TOUCHPAD; //Start in touchpad Mode
tfb = (u16*)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL);
//Load overlay files from sdmc for easier testing
FILE *texture = fopen("touchOverlay.bin", "rb");
if(!texture)
Sys_Error("Could not open touchpadOverlay.bin\n");
fseek(texture, 0, SEEK_END);
int size = ftell(texture);
fseek(texture, 0, SEEK_SET);
touchOverlay = malloc(size);
fread(touchOverlay, 1, size, texture);
fclose(texture);
}
void Touch_DrawOverlay()
{
int x, y;
for(x=0; x<320; x++){
for(y=0; y<240;y++){
tfb[(x*240 + (239 - y))] = touchOverlay[(y*320 + x)];
}
}
}
void Touch_Update(){
if(lastKey){
Key_Event(lastKey, false);
lastKey = 0;
}
if(hidKeysDown() & KEY_TOUCH){
hidTouchRead(&touch);
tick = Sys_FloatTime();
}
if(hidKeysUp() & KEY_TOUCH){
Touch_ProcessTap();
}
}
void Touch_ProcessTap()
{
if(touch.px > 268 && touch.py > 14 && touch.py < 226)
Touch_SideBarTap();
}
void Touch_SideBarTap()
{
uint16_t y = (touch.py - 14)/42;
lastKey = K_AUX9 + y;
Key_Event(lastKey, true);
}

14
source/ctr/touch_ctr.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef __TOUCH__
#define __TOUCH__
//Touchscreen mode identifiers
#define TMODE_TOUCHPAD 1
#define TMODE_SETTINGS 2
void Touch_TouchpadTap();
void Touch_ProcessTap();
void Touch_DrawOverlay();
void Touch_Init();
void Touch_Update();
#endif

85
source/ctr/vid.h Normal file
View file

@ -0,0 +1,85 @@
/*
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.
*/
// vid.h -- video driver defs
#define VID_CBITS 6
#define VID_GRADES (1 << VID_CBITS)
// a pixel can be one, two, or four bytes
typedef byte pixel_t;
typedef struct vrect_s
{
int x,y,width,height;
struct vrect_s *pnext;
} vrect_t;
typedef struct
{
pixel_t *buffer; // invisible buffer
pixel_t *colormap; // 256 * VID_GRADES size
unsigned short *colormap16; // 256 * VID_GRADES size
int fullbright; // index of first fullbright color
unsigned rowbytes; // may be > width if displayed in a window
unsigned width;
unsigned height;
float aspect; // width / height -- < 0 is taller than wide
int numpages;
int recalc_refdef; // if true, recalc vid-based stuff
pixel_t *conbuffer;
int conrowbytes;
unsigned conwidth;
unsigned conheight;
int maxwarpwidth;
int maxwarpheight;
pixel_t *direct; // direct drawing to framebuffer, if not
// NULL
} viddef_t;
extern viddef_t vid; // global video state
extern unsigned short d_8to16table[256];
extern unsigned d_8to24table[256];
extern void (*vid_menudrawfn)(void);
extern void (*vid_menukeyfn)(int key);
void VID_SetPalette (unsigned char *palette);
// called at startup and after any gamma correction
void VID_ShiftPalette (unsigned char *palette);
// called for bonus and pain flashes, and for underwater color changes
void VID_Init (unsigned char *palette);
// Called at startup to set up translation tables, takes 256 8 bit RGB values
// the palette data will go away after the call, so it must be copied off if
// the video driver will need it again
void VID_Shutdown (void);
// Called at shutdown
void VID_Update (vrect_t *rects);
// flushes the given rectangles from the view buffer to the screen
int VID_SetMode (int modenum, unsigned char *palette);
// sets the mode; only used by the Quake engine for resetting to mode 0 (the
// base mode) on memory allocation failures
void VID_HandlePause (qboolean pause);
// called only on Win32, when pause happens, so the mouse can be released