├── README ├── CMakeLists.txt ├── JM.H ├── SNDSHOV.H ├── IDLIB_SDL.H ├── matrix.h ├── MEMMGR.H ├── JM_SB.H ├── MEMMGR.C ├── GRAPHHOV.H ├── HOVSCALE.C ├── matrix.cpp ├── HOVTEXT.C ├── JM_SB.C ├── HOVERDEF.H ├── IDLIB.H ├── IDLIBC_SHADERS.C ├── COPYING ├── IDLIBC.C ├── HOVTRACE.C ├── IDLIBC_SDL.C ├── IDLIBC_GL.C └── HOVLOOP.C /README: -------------------------------------------------------------------------------- 1 | Hovertank 3-D 2 | ============= 3 | 4 | This repostiory contains a source code port of Hovertank 3-D to SDL. 5 | Currently builds under windows visual studio but work will be done to port 6 | to other platforms. 7 | 8 | It is released under the GNU GPLv2. Please see COPYING for license details. 9 | 10 | This release does not affect the game data files. You will need to legally 11 | acquire the game data in order to use the exe built from this source code. 12 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | 3 | 4 | include(FindPkgConfig) 5 | 6 | project(game) 7 | 8 | find_package(OpenGL REQUIRED) 9 | 10 | if (WIN32) 11 | find_file(SDL2_INCLUDE_DIRS NAME SDL.h HINTS SDL2) 12 | find_library(SDL2_LIBRARIES NAME SDL2) 13 | find_library(SDL2MAIN_LIBRARIES NAME SDL2) 14 | endif (WIN32) 15 | 16 | if (UNIX) 17 | pkg_search_module(SDL2 REQUIRED sdl2) 18 | endif (UNIX) 19 | 20 | include_directories( 21 | ${SDL2_INCLUDE_DIRS} 22 | ) 23 | 24 | add_executable(game WIN32 25 | MEMMGR.C 26 | IDLIBC.C 27 | IDLIBC_SDL.C 28 | IDLIBC_SHADERS.C 29 | IDLIBC_GL.C 30 | HOVDRAW.C 31 | HOVTRACE.C 32 | HOVSCALE.C 33 | HOVLOOP.C 34 | HOVACTS.C 35 | JM_SB.C 36 | HOVMAIN.C 37 | matrix.cpp 38 | ) 39 | 40 | target_link_libraries(game 41 | ${SDL2_LIBRARIES} 42 | ${SDL2MAIN_LIBRARIES} 43 | ${OPENGL_LIBRARIES} 44 | ) 45 | -------------------------------------------------------------------------------- /JM.H: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | // 20 | // jm.h 21 | // Constants, structs, and function prototypes for my music stuff 22 | // 23 | 24 | #ifndef __jm__ 25 | #define __jm__ 26 | 27 | typedef uint16_t word; 28 | typedef uint32_t longword; 29 | 30 | #define false 0 31 | #define true 1 32 | #define nil 0L 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /SNDSHOV.H: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | // 20 | // From Sound Editor v1.31 by Lane Roath 21 | // 22 | 23 | #define FIRESND 1 24 | #define BUMPWALLSND 2 25 | #define AFTERBURNSND 3 26 | #define SHOOTWALLSND 4 27 | #define SHOOTTHINGSND 5 28 | #define SAVEHOSTAGESND 6 29 | #define HOSTAGEDEADSND 7 30 | #define LOWTIMESND 8 31 | #define TAKEDAMAGESND 9 32 | #define NUKESND 10 33 | #define WARPGATESND 11 34 | #define PLAYERDEADSND 12 35 | #define GUNREADYSND 13 36 | #define MAXPOWERSND 14 37 | #define LASTHOSTAGESND 15 38 | #define ARMORUPSND 16 39 | #define TIMESCORESND 17 40 | #define GUYSCORESND 18 41 | #define STARTGAMESND 19 42 | #define HIGHSCORESND 20 43 | -------------------------------------------------------------------------------- /IDLIB_SDL.H: -------------------------------------------------------------------------------- 1 | 2 | #ifndef IDLIB_SDL 3 | #define IDLIB_SDL 4 | 5 | #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) 6 | #ifndef WIN32_LEAN_AND_MEAN 7 | #define WIN32_LEAN_AND_MEAN 1 8 | #endif 9 | #include 10 | #endif 11 | #include 12 | #include "glext.h" 13 | 14 | #define GLDECLARE(x) extern PFN##x##PROC x 15 | #define GLDEFINE(x) PFN##x##PROC x 16 | #define GLGETPROC(x) x = (PFN##x##PROC)SDL_GL_GetProcAddress(#x); assert(x); 17 | 18 | #define _GLDECLARE(x) extern PFN##x##PROC _##x 19 | #define _GLDEFINE(x) PFN##x##PROC _##x 20 | #define _GLGETPROC(x) _##x = (PFN##x##PROC)SDL_GL_GetProcAddress(#x); assert(x); 21 | 22 | typedef struct { 23 | int16_t height; 24 | int16_t location[256]; 25 | uint8_t width[256]; 26 | int16_t total_width; 27 | GLuint texture; 28 | } font_t; 29 | 30 | extern SDL_Window * window; 31 | extern int windowFullscreen; 32 | extern int windowWidth, windowHeight; 33 | extern int viewportX, viewportY; 34 | extern int viewportWidth, viewportHeight; 35 | 36 | /* 37 | IDLIBC_SHADERS 38 | */ 39 | 40 | void SHADERS_Init(void); 41 | void UseColorShader(float * matrix, float * vertices, int xor, uint8_t color); 42 | void UseTextureShader(float * matrix, float * vertices, int blend, unsigned int texture, float * texcoord); 43 | void UseFontShader(float * matrix, float * vertices, int blend, uint8_t color, GLuint texture, float * texcoord); 44 | void UseFadeShader(float fade, GLuint texture, float * vertices, float * texcoords); 45 | 46 | #endif//IDLIB_SDL 47 | -------------------------------------------------------------------------------- /matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef MATRIX_H 2 | #define MATRIX_H 3 | 4 | typedef struct { 5 | float m[16]; 6 | } matrix4x4_t; 7 | 8 | void Matrix4x4_SetIdentity(matrix4x4_t * matrix); 9 | 10 | void Matrix4x4_SetTranslate(matrix4x4_t * matrix, float x, float y, float z); 11 | 12 | void Matrix4x4_SetScale(matrix4x4_t * matrix, float x, float y, float z); 13 | 14 | // rotation is clockwise: 15 | // xaxis rotation is +z towards +y 16 | // yaxis rotation is +x towards +z 17 | // zaxis rotation is +y towards +x 18 | 19 | void Matrix4x4_SetRotate(matrix4x4_t * matrix, float x, float y, float z, float radians); 20 | 21 | void Matrix4x4_SetScreen(matrix4x4_t * matrix, float width, float height); 22 | 23 | void Matrix4x4_SetProject(matrix4x4_t * matrix, float fovUp, float fovDown, float fovLeft, float fovRight, float zNear, float zFar); 24 | 25 | // first matrix is transformed by the base matrix 26 | // in the pipeline, a vector is transformed by first matrix and then by base matrix 27 | // examples: 28 | // Matrix4x4_Multiply(mv, view, model); 29 | // Matrix4x4_Multiply(mvp, projection, mv); 30 | 31 | void Matrix4x4_Multiply(matrix4x4_t * result, const matrix4x4_t * base, const matrix4x4_t * first); 32 | 33 | void Matrix4x4_FrontTranslate(matrix4x4_t * matrix, float x, float y, float z); 34 | void Matrix4x4_FrontScale(matrix4x4_t * matrix, float x, float y, float z); 35 | void Matrix4x4_FrontRotate(matrix4x4_t * matrix, float x, float y, float z, float radians); 36 | 37 | void Matrix4x4_BackTranslate(matrix4x4_t * matrix, float x, float y, float z); 38 | void Matrix4x4_BackScale(matrix4x4_t * matrix, float x, float y, float z); 39 | void Matrix4x4_BackRotate(matrix4x4_t * matrix, float x, float y, float z, float radians); 40 | 41 | #endif//MATRIX_H -------------------------------------------------------------------------------- /MEMMGR.H: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | typedef void * memptr; 20 | 21 | extern unsigned totalmem; // total paragraphs available 22 | 23 | //#define GUARDBYTES 16 24 | 25 | //========================================================================== 26 | 27 | // 28 | // public prototypes 29 | // 30 | void MMStartup (void); 31 | void MMShutdown (void); 32 | #ifdef GUARDBYTES 33 | void _MMGetPtr (memptr *baseptr,long size,const char * fname, int line); 34 | #define MMGetPtr(baseptr,size) _MMGetPtr(baseptr,size,__FILE__,__LINE__) 35 | #else 36 | void MMGetPtr (memptr *baseptr,long size); 37 | #endif 38 | void MMFreePtr (memptr *baseptr); 39 | void MMSetPurge (memptr *baseptr, int purge); 40 | void MMSortMem (void); 41 | unsigned MMUnusedMemory (void); 42 | unsigned MMTotalFree (void); 43 | 44 | #ifdef GUARDBYTES 45 | void MMValidatePtr (memptr *baseptr); 46 | void MMValidateAll (); 47 | #else 48 | #define MMValidatePtr(baseptr) 49 | #define MMValidateAll() 50 | #endif 51 | 52 | -------------------------------------------------------------------------------- /JM_SB.H: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | // 20 | // jm_sb.h 21 | // Constants, structs, and function prototypes for my SoundBlaster stuff 22 | // 23 | typedef uint8_t byte; 24 | typedef uint16_t boolean; 25 | 26 | 27 | #ifndef __jm__ 28 | #include "JM.H" 29 | #endif 30 | 31 | #ifndef __jm_sb__ 32 | #define __jm_sb__ 33 | 34 | // Registers for the Sound Blaster card - needs to be offset by n0 35 | #define sbReset 0x206 36 | #define sbReadData 0x20a 37 | #define sbWriteCmd 0x20c 38 | #define sbWriteData 0x20c 39 | #define sbWriteStat 0x20c 40 | #define sbDataAvail 0x20e 41 | 42 | 43 | #pragma pack(push, 1) 44 | typedef struct 45 | { 46 | longword offset,length, 47 | hertz; 48 | byte bits, 49 | reference; 50 | } SampledSound; 51 | #pragma pack(pop) 52 | 53 | extern byte * jmData; 54 | extern int jmDataLength; 55 | extern int jmDataFreq; 56 | extern float jmDataTime; 57 | 58 | // 59 | // Function prototypes 60 | // 61 | 62 | extern void jmStartSB(void),jmStopSB(void), 63 | jmSetSBInterrupt(int), 64 | jmSetSamplePtr(SampledSound *), 65 | jmPlaySample(int),jmStopSample(void); 66 | extern boolean jmDetectSoundBlaster(int), 67 | jmSamplePlaying(void); 68 | 69 | void jmShutSB(void); 70 | 71 | #endif//__jm_sb__ 72 | -------------------------------------------------------------------------------- /MEMMGR.C: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "MEMMGR.H" 6 | 7 | 8 | 9 | unsigned totalmem; // total paragraphs available 10 | 11 | 12 | //========================================================================== 13 | 14 | // 15 | // public prototypes 16 | // 17 | 18 | #define MAX_TRACKED 1024 19 | static memptr allocation[MAX_TRACKED]; 20 | 21 | void MMStartup (void) { } 22 | 23 | void MMShutdown (void) { 24 | MMValidateAll(); 25 | } 26 | 27 | #ifdef GUARDBYTES 28 | void _MMGetPtr (memptr *baseptr,long size, const char * fname, int line) 29 | { 30 | assert(size>0); 31 | size += GUARDBYTES*2+8; 32 | unsigned char * bytes = (unsigned char*)malloc(size); 33 | memset(bytes, 0xFFFFFFFF, size); 34 | *(int*)(bytes+GUARDBYTES) = size; 35 | *(int*)(bytes+size-GUARDBYTES-4) = size; 36 | *baseptr = bytes + GUARDBYTES + 4; 37 | 38 | int i = 0; 39 | for (i = 0; i < MAX_TRACKED; i++) 40 | { 41 | if (!allocation[i]) 42 | { 43 | allocation[i] = *baseptr; 44 | break; 45 | } 46 | } 47 | assert(i < MAX_TRACKED); 48 | } 49 | #else 50 | void MMGetPtr (memptr *baseptr,long size) 51 | { 52 | *baseptr = malloc(size); 53 | } 54 | #endif 55 | 56 | void MMFreePtr (memptr *baseptr) 57 | { 58 | #ifdef GUARDBYTES 59 | MMValidatePtr(baseptr); 60 | 61 | unsigned char * bytes = (unsigned char*)*baseptr; 62 | bytes -= GUARDBYTES+4; 63 | 64 | int i; 65 | for (i = 0; i < MAX_TRACKED; i++) 66 | { 67 | if (allocation[i] == *baseptr) 68 | { 69 | allocation[i] = 0; 70 | break; 71 | } 72 | } 73 | assert(i < MAX_TRACKED); 74 | 75 | free(bytes); 76 | *baseptr = 0; 77 | #else 78 | free(*baseptr); 79 | *baseptr = 0; 80 | #endif 81 | } 82 | 83 | void MMSetPurge (memptr *baseptr, int purge) { } 84 | 85 | void MMSortMem (void) { } 86 | 87 | unsigned MMUnusedMemory (void) { return 0; } 88 | 89 | unsigned MMTotalFree (void) { return 0; } 90 | 91 | 92 | #ifdef GUARDBYTES 93 | void MMValidatePtr (memptr *baseptr) 94 | { 95 | unsigned char * bytes = (unsigned char*)*baseptr; 96 | bytes -= GUARDBYTES+4; 97 | 98 | int size = *(int*)(bytes + GUARDBYTES); 99 | assert(size > GUARDBYTES*2); 100 | int size2 = *(int*)(bytes+size-GUARDBYTES-4); 101 | assert(size==size2); 102 | 103 | for (int i = 0; i < GUARDBYTES; i++) 104 | { 105 | assert(bytes[i] == 0xff); 106 | assert(bytes[size-i-1] == 0xff); 107 | } 108 | } 109 | 110 | void MMValidateAll() 111 | { 112 | for (int i = 0; i < MAX_TRACKED; i++) 113 | { 114 | if (allocation[i]) 115 | { 116 | MMValidatePtr(&allocation[i]); 117 | } 118 | } 119 | } 120 | #endif 121 | -------------------------------------------------------------------------------- /GRAPHHOV.H: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | ////////////////////////////////////// 20 | // 21 | // Graphics DEFINE file for .HOV 22 | // IGRAB-ed on Thu Dec 02 11:07:46 1993 23 | // 24 | ////////////////////////////////////// 25 | 26 | #define MAN1PIC 0 27 | #define MAN2PIC 1 28 | #define MANDIE1PIC 2 29 | #define MANDIE2PIC 3 30 | #define MANDIE3PIC 4 31 | #define MANDIE4PIC 5 32 | #define MANDIE5PIC 6 33 | #define WOMAN1PIC 7 34 | #define WOMAN2PIC 8 35 | #define WOMANDIE1PIC 9 36 | #define WOMANDIE2PIC 10 37 | #define WOMANDIE3PIC 11 38 | #define WOMANDIE4PIC 12 39 | #define WOMANDIE5PIC 13 40 | #define BIGSHOTPIC 14 41 | #define PSHOTPIC 15 42 | #define MSHOTPIC 16 43 | #define SHOTDIE1PIC 17 44 | #define SHOTDIE2PIC 18 45 | #define SHOTDIE3PIC 19 46 | #define SHOTDIE4PIC 20 47 | #define SHOTDIE5PIC 21 48 | #define TANK1PIC 22 49 | #define TANKDIE1PIC 23 50 | #define TANKDIE2PIC 24 51 | #define TANKDIE3PIC 25 52 | #define TANKDIE4PIC 26 53 | #define TANKDIE5PIC 27 54 | #define MUTANT1PIC 28 55 | #define MUTANT2PIC 29 56 | #define MUTANT3PIC 30 57 | #define MUTANT4PIC 31 58 | #define MUTANTDIE1PIC 32 59 | #define MUTANTDIE2PIC 33 60 | #define MUTANTDIE3PIC 34 61 | #define MUTANTDIE4PIC 35 62 | #define MUTANTDIE5PIC 36 63 | #define MUTANTSWINGPIC 37 64 | #define MUTANTHITPIC 38 65 | #define SHIELD1PIC 39 66 | #define SHIELD2PIC 40 67 | #define DRONE1PIC 41 68 | #define DRONE2PIC 42 69 | #define DRONE3PIC 43 70 | #define DRONE4PIC 44 71 | #define DRONEDIE1PIC 45 72 | #define DRONEDIE2PIC 46 73 | #define DRONEDIE3PIC 47 74 | #define DRONEDIE4PIC 48 75 | #define DRONEDIE5PIC 49 76 | #define WARP1PIC 50 77 | #define WARP2PIC 51 78 | #define WARP3PIC 52 79 | #define WARP4PIC 53 80 | #define DASHPIC 54 81 | #define DIGIT0PIC 55 82 | #define DIGIT1PIC 56 83 | #define DIGIT2PIC 57 84 | #define DIGIT3PIC 58 85 | #define DIGIT4PIC 59 86 | #define DIGIT5PIC 60 87 | #define DIGIT6PIC 61 88 | #define DIGIT7PIC 62 89 | #define DIGIT8PIC 63 90 | #define DIGIT9PIC 64 91 | #define SHIELDFULLPIC 65 92 | #define SHIELDHALFPIC 66 93 | #define SHIELDLOWPIC 67 94 | #define EMPTYGUYPIC 68 95 | #define SAVEDGUYPIC 69 96 | #define DEADGUYPIC 70 97 | #define REARMINGPIC 71 98 | #define READYPIC 72 99 | #define CHARGINGPIC 73 100 | #define MAXPOWERPIC 74 101 | #define ENDPIC 75 102 | #define LOGOPIC 76 103 | #define STARSPIC 77 104 | #define TITLEPIC 78 105 | #define DEATHPIC 79 106 | #define MISSIONPIC 80 107 | #define UFAPIC 81 108 | #define MADUFAPIC 82 109 | 110 | 111 | 112 | // 113 | // Amount of each data item 114 | // 115 | #define NUMCHUNKS 86 116 | #define NUMFONT 0 117 | #define NUMFONTM 1 118 | #define NUMPICS 83 119 | #define NUMPICM 0 120 | #define NUMSPRITES 0 121 | #define NUMTILE8 72 122 | #define NUMTILE8M 0 123 | #define NUMTILE16 0 124 | #define NUMTILE16M 0 125 | #define NUMTILE32 0 126 | #define NUMTILE32M 0 127 | // 128 | // File offsets for data items 129 | // 130 | #define STRUCTPIC 0 131 | 132 | #define STARTFONT 1 133 | #define STARTFONTM 1 134 | #define STARTPICS 2 135 | #define STARTPICM 85 136 | #define STARTSPRITES 85 137 | #define STARTTILE8 85 138 | #define STARTTILE8M 86 139 | #define STARTTILE16 86 140 | #define STARTTILE16M 86 141 | #define STARTTILE32 86 142 | #define STARTTILE32M 86 143 | 144 | // 145 | // Thank you for using IGRAB! 146 | // 147 | -------------------------------------------------------------------------------- /HOVSCALE.C: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "HOVERDEF.H" 20 | 21 | #define scaleshape gltexture 22 | 23 | #define MAXPICHEIGHT 256 // tallest pic to be scaled 24 | 25 | #define BASESCALE 64 // normal size 26 | #define MAXSCALE 256 // largest scale possible 27 | #define SCALESTEP 3 28 | #define DISCREETSCALES (MAXSCALE/SCALESTEP) 29 | 30 | memptr basetableseg,screentableseg; // segment of basetables and screentables 31 | unsigned basetables[DISCREETSCALES], // offsets in basetableseg 32 | screentables[DISCREETSCALES]; // offsets in screentableseg 33 | 34 | int scalexl = 0, 35 | scalexh = 319, 36 | scaleyl = 0, 37 | scaleyh = 144; 38 | 39 | unsigned scaleblockwidth, 40 | scaleblockheight, 41 | scaleblockdest; 42 | 43 | void SC_Setup(void) 44 | { 45 | #ifdef OLDDRAW 46 | 47 | unsigned mask,i,step,scale,space; 48 | unsigned char *baseptr, *screenptr; 49 | unsigned offset1,offset2,size; 50 | 51 | // 52 | // fast ploting tables 53 | // 54 | #if 0 55 | mask = 128; 56 | for (i=0;i<320;i++) 57 | { 58 | bytetable[i]=i/8; 59 | masktable[i]=mask; 60 | if (!(mask>>=1)) 61 | mask = 128; 62 | } 63 | #endif 64 | 65 | // 66 | // fast scaling tables 67 | // 68 | 69 | offset1 = offset2 = 0; 70 | 71 | for (step=0;step=DISCREETSCALES) 122 | scalechop = DISCREETSCALES-1; 123 | 124 | basetoscreenptr = (unsigned char*)basetableseg + basetables[scalechop]; 125 | screentobaseptr = (unsigned char*)screentableseg + screentables[scalechop]; 126 | 127 | // 128 | // figure bounding rectangle for scaled image 129 | // 130 | fullwidth = ((scaleshape*)shape)->width; 131 | fullheight = ((scaleshape*)shape)->height; 132 | 133 | scalewidth = fullwidth*((scalechop+1)*SCALESTEP)/BASESCALE; //basetoscreenptr[fullwidth-1]; 134 | scaleheight = basetoscreenptr[fullheight-1]; 135 | 136 | xl=x-scalewidth/2; 137 | xh=xl+scalewidth-1; 138 | yl=y-scaleheight/2; 139 | yh=yl+scaleheight-1; 140 | 141 | 142 | // off screen? 143 | 144 | if (xl>scalexh || xhscaleyh || yhscalexh) 155 | sxh=scalexh; 156 | else 157 | sxh=xh; 158 | 159 | // 160 | // clip both sides to zbuffer 161 | // 162 | sx=sxl; 163 | while (zbuffer[sx]>scale && sx<=sxh) 164 | sx++; 165 | sxl=sx; 166 | 167 | sx=sxh; 168 | while (zbuffer[sx]>scale && sx>sxl) 169 | sx--; 170 | sxh=sx; 171 | 172 | if (sxl>sxh) 173 | return 0; // behind a wall 174 | 175 | // 176 | // save block info for background erasing 177 | // 178 | screencorner = screenofs+yl*linewidth; 179 | 180 | scaleblockdest = screencorner + sxl/8; 181 | scaleblockwidth = sxh/8-sxl/8+1; 182 | scaleblockheight = yh-yl+1; 183 | 184 | 185 | // 186 | // start drawing 187 | // 188 | 189 | DrawScaledShape(sxl, yl, sxh, yh, 190 | screentobaseptr[sxl-xl], screentobaseptr[sxh-xl], 191 | shape); 192 | 193 | 194 | #else 195 | DrawShape(x, y, scale, shape); 196 | #endif 197 | return 1; 198 | } 199 | 200 | void SC_FreeShape (memptr shapeptr) 201 | { 202 | } 203 | -------------------------------------------------------------------------------- /matrix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "matrix.h" 3 | 4 | #include 5 | 6 | void Matrix4x4_SetIdentity(matrix4x4_t * matrix) 7 | { 8 | float *m = matrix->m; 9 | memset(m, 0, sizeof(matrix->m)); 10 | m[0] = m[5] = m[10] = m[15] = 1.f; 11 | } 12 | 13 | void Matrix4x4_SetTranslate(matrix4x4_t * matrix, float x, float y, float z) 14 | { 15 | float *m = matrix->m; 16 | memset(m, 0, sizeof(matrix->m)); 17 | m[0] = m[5] = m[10] = m[15] = 1.f; 18 | m[12] = x; m[13] = y; m[14] = z; 19 | } 20 | 21 | void Matrix4x4_SetScale(matrix4x4_t * matrix, float x, float y, float z) 22 | { 23 | float *m = matrix->m; 24 | memset(m, 0, sizeof(matrix->m)); 25 | m[0] = x; m[5] = y; m[10] = z; m[15] = 1.f; 26 | } 27 | 28 | void Matrix4x4_SetRotate(matrix4x4_t * matrix, float x, float y, float z, float radians) 29 | { 30 | float *m = matrix->m; 31 | float c = cosf(radians); 32 | float s = sinf(radians); 33 | float ic = 1.f - c; 34 | float x2 = x*x; 35 | float y2 = y*y; 36 | float z2 = z*z; 37 | float icx = ic*x; 38 | float icy = ic*y; 39 | float xs = x*s; 40 | float ys = y*s; 41 | float zs = z*s; 42 | float cx2 = c*x2; 43 | float cy2 = c*y2; 44 | float cz2 = c*z2; 45 | float icxy = icx*y; 46 | float icxz = icx*z; 47 | float icyz = icy*z; 48 | 49 | m[ 0] = x2 + cy2 + cz2; 50 | m[ 1] = icxy - zs; 51 | m[ 2] = icxz + ys; 52 | m[ 3] = 0; 53 | 54 | m[ 4] = icxy + zs; 55 | m[ 5] = cx2 + y2 + cz2; 56 | m[ 6] = icyz - xs; 57 | m[ 7] = 0; 58 | 59 | m[ 8] = icxz - ys; 60 | m[ 9] = icyz + xs; 61 | m[10] = cx2 + cy2 + z2; 62 | m[11] = 0; 63 | 64 | m[12] = 0; 65 | m[13] = 0; 66 | m[14] = 0; 67 | m[15] = 1.f; 68 | } 69 | 70 | void Matrix4x4_SetScreen(matrix4x4_t * matrix, float width, float height) 71 | { 72 | float *m = matrix->m; 73 | memset(m, 0, sizeof(matrix->m)); 74 | m[0] = 2.f/width; 75 | m[5] = -2.f/height; 76 | m[10] = m[13] = m[15] = 1.f; 77 | m[12] = -1.f; 78 | } 79 | 80 | #define PI 3.141592653589793f 81 | 82 | void Matrix4x4_SetProject(matrix4x4_t * matrix, float fovUp, float fovDown, float fovLeft, float fovRight, float zNear, float zFar) 83 | { 84 | float *m = matrix->m; 85 | memset(m, 0, sizeof(matrix->m)); 86 | float d = zFar - zNear; 87 | float rd = 1.f / d; 88 | 89 | float tanUp = tanf(fovUp); 90 | float tanDown = tanf(fovDown); 91 | float tanLeft = tanf(fovLeft); 92 | float tanRight = tanf(fovRight); 93 | float xScale = 2.f / (tanLeft + tanRight); 94 | float yScale = 2.f / (tanUp + tanDown); 95 | 96 | m[0] = xScale; 97 | m[5] = yScale; 98 | m[8] = -0.5f * xScale * (tanLeft - tanRight); 99 | m[9] = 0.5f * yScale * (tanUp - tanDown); 100 | m[10] = -(zNear + zFar) * rd; 101 | m[11] = -1.f; 102 | m[14] = -2.f * zFar * zNear * rd; 103 | } 104 | 105 | void Matrix4x4_Multiply(matrix4x4_t * result, const matrix4x4_t * base, const matrix4x4_t * first) 106 | { 107 | const float *a = base->m; 108 | const float *b = first->m; 109 | float *out = result->m; 110 | float a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], 111 | a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], 112 | a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], 113 | a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; 114 | 115 | float b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; 116 | out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; 117 | out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; 118 | out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; 119 | out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; 120 | 121 | b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; 122 | out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; 123 | out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; 124 | out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; 125 | out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; 126 | 127 | b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; 128 | out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; 129 | out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; 130 | out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; 131 | out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; 132 | 133 | b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; 134 | out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; 135 | out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; 136 | out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; 137 | out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; 138 | } 139 | 140 | 141 | void Matrix4x4_FrontTranslate(matrix4x4_t * matrix, float x, float y, float z) 142 | { 143 | // TODO optimize 144 | matrix4x4_t temp; 145 | Matrix4x4_SetTranslate(&temp, x, y, z); 146 | Matrix4x4_Multiply(matrix, matrix, &temp); 147 | } 148 | 149 | void Matrix4x4_FrontScale(matrix4x4_t * matrix, float x, float y, float z) 150 | { 151 | // TODO optimize 152 | matrix4x4_t temp; 153 | Matrix4x4_SetScale(&temp, x, y, z); 154 | Matrix4x4_Multiply(matrix, matrix, &temp); 155 | } 156 | 157 | void Matrix4x4_FrontRotate(matrix4x4_t * matrix, float x, float y, float z, float radians) 158 | { 159 | // TODO optimize 160 | matrix4x4_t temp; 161 | Matrix4x4_SetRotate(&temp, x, y, z, radians); 162 | Matrix4x4_Multiply(matrix, matrix, &temp); 163 | } 164 | 165 | void Matrix4x4_BackTranslate(matrix4x4_t * matrix, float x, float y, float z) 166 | { 167 | // TODO optimize 168 | matrix4x4_t temp; 169 | Matrix4x4_SetTranslate(&temp, x, y, z); 170 | Matrix4x4_Multiply(matrix, &temp, matrix); 171 | } 172 | 173 | void Matrix4x4_BackScale(matrix4x4_t * matrix, float x, float y, float z) 174 | { 175 | // TODO optimize 176 | matrix4x4_t temp; 177 | Matrix4x4_SetScale(&temp, x, y, z); 178 | Matrix4x4_Multiply(matrix, &temp, matrix); 179 | } 180 | 181 | void Matrix4x4_BackRotate(matrix4x4_t * matrix, float x, float y, float z, float radians) 182 | { 183 | // TODO optimize 184 | matrix4x4_t temp; 185 | Matrix4x4_SetRotate(&temp, x, y, z, radians); 186 | Matrix4x4_Multiply(matrix, &temp, matrix); 187 | } 188 | 189 | -------------------------------------------------------------------------------- /HOVTEXT.C: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | char *levnames[20] = 20 | {/*......................................*/ 21 | "Zone 1: Langston Research Facility", 22 | "Zone 2: Gardens of Marvin M. Mitchell", 23 | "Zone 3: Caves, Brazos de la Madre", 24 | "Zone 4: Fort Smith", 25 | "Zone 5: Coyote Canyon", 26 | "Zone 6: Santa Maria Cathedral", 27 | "Zone 7: Pax Humana Commune", 28 | "Zone 8: Sewers below New Trenton", 29 | "Zone 9: Old UFA Headquarters", 30 | "Zone 10: Braker's Mountain", 31 | "Zone 11: Wounded Village", 32 | "Zone 12: Murder Hill", 33 | "Zone 13: TerraChem Corp.", 34 | "Zone 14: Gulf Tech University", 35 | "Zone 15: Agromatic Inc. Farm", 36 | "Zone 16: National Agency for Defense", 37 | "Zone 17: Jackson International Airport", 38 | "Zone 18: Museum of Modern Art", 39 | "Zone 19: AUF Headquarters", 40 | "Zone 20: UFA Headquarters", 41 | }; 42 | 43 | 44 | char *levtext[20] = 45 | {/*......................................*/ 46 | "Your first assignment is to rescue a\n" 47 | "bunch of scientists who have\n" 48 | "barracaded themselves inside the\n" 49 | "Langston Research Facility. They were\n" 50 | "working on a new, clean fuel until\n" 51 | "some big oil corporations decided to\n" 52 | "buy Langston out. Now insiders say\n" 53 | "the corporation is going to nuke them.\n" 54 | 55 | ,/*......................................*/ 56 | "The Mitchell estate is home to many of\n" 57 | "the world's most famous activists,\n" 58 | "philanthropists, and do-gooders.\n" 59 | "We've just found out that a group of\n" 60 | "extremely rich industrialists have\n" 61 | "funded a tactical strike on the estate\n" 62 | "after some of the activists irritated\n" 63 | "some of their interests.\n" 64 | 65 | ,/*......................................*/ 66 | "A group of terrorists known as The Dark\n" 67 | "Legion are holding a bunch of children\n" 68 | "hostage until their demands are met.\n" 69 | "The goverment has decided, with their\n" 70 | "usual compassion, to nuke the Legion\n" 71 | "along with their hostages. Get the\n" 72 | "hostages out of there.\n" 73 | 74 | ,/*......................................*/ 75 | "The last renegades of the local\n" 76 | "resistance are imprisoned for holding\n" 77 | "rallies and publishing their anti-\n" 78 | "government pamphlets. A superpower is\n" 79 | "is planning to nuke Fort Smith for its\n" 80 | "strategic importance. We want those\n" 81 | "renegades.\n" 82 | 83 | ,/*......................................*/ 84 | "A brilliant scientist and his daughter\n" 85 | "are living on a missile site in the\n" 86 | "canyon. The site is a military target,\n" 87 | "and we want you to get Professor\n" 88 | "Phillips back safely to Headquarters.\n" 89 | 90 | ,/*......................................*/ 91 | "A group of priests have been tending\n" 92 | "the dying at the cathedral, even\n" 93 | "though their area is likely to be\n" 94 | "bombed again. The mutants swarming\n" 95 | "the area are insane. Be careful!\n" 96 | 97 | ,/*......................................*/ 98 | "This commune of peace demonstrators is\n" 99 | "about to be toasted by the NMC -- the\n" 100 | "National Munitions Corporation. Pax\n" 101 | "Humana has been a thorn in their side\n" 102 | "for many years. The thorn is about to\n" 103 | "be removed...by nuclear means.\n" 104 | 105 | ,/*......................................*/ 106 | "This city's sewers hold the survivors\n" 107 | "of the last nuclear attack. Unlucky\n" 108 | "for them, the last one wasn't the\n" 109 | "last one....\n" 110 | 111 | ,/*......................................*/ 112 | "Some operatives remain at the old\n" 113 | "headquarters after the move, and\n" 114 | "those looking for us have finally\n" 115 | "located the old base. You'll have\n" 116 | "to work fast.\n" 117 | 118 | ,/*......................................*/ 119 | "A dangerous horde of mutants are\n" 120 | "holding humans prisoner inside the\n" 121 | "mountain. Rescue them before the\n" 122 | "area is 'sanitized.'\n" 123 | 124 | ,/*......................................*/ 125 | "Drones have gone rampant and are\n" 126 | "killing the population of this\n" 127 | "village. Before the situation is\n" 128 | "'gotten under control,' you need to\n" 129 | "get those people out of there.\n" 130 | 131 | ,/*......................................*/ 132 | "A tank brigade is hunting down AWOL\n" 133 | "soldiers. Little do they know that\n" 134 | "the whole area is about be baked by\n" 135 | "enemy missiles. Those soldiers have\n" 136 | "some interesting information that we\n" 137 | "would like to acquire.\n" 138 | 139 | ,/*......................................*/ 140 | "There are engineers trapped in the\n" 141 | "TerraChem building. Get them back so\n" 142 | "they can testify against TerraChem.\n" 143 | "But hurry, the whole building's gonna\n" 144 | "blow!\n" 145 | 146 | ,/*......................................*/ 147 | "Terrorists are about to bomb Gulf Tech\n" 148 | "University off the face of the earth.\n" 149 | "We haven't been able to reach the\n" 150 | "scientists there. Get them out of there!\n" 151 | 152 | ,/*......................................*/ 153 | "The Agromatic Inc. Corporate farm is\n" 154 | "being nuked by their competitors at\n" 155 | "at TerraTronic Inc. Get the innocent\n" 156 | "farmers to safety.\n" 157 | 158 | ,/*......................................*/ 159 | "Some of our UFA spies are trapped in\n" 160 | "NAD headquarters. Rescue them before\n" 161 | "the enemy missiles get there.\n" 162 | 163 | ,/*......................................*/ 164 | "The airport is under siege by\n" 165 | "terrorist forces. Get the civilians \n" 166 | "out before the Company takes care of\n" 167 | "the situation.\n" 168 | 169 | ,/*......................................*/ 170 | "The Museum is going to be bombed by\n" 171 | "by Dadaists. The bombing is their\n" 172 | "form of anti-expression. They've\n" 173 | "barred the exits and the missiles are\n" 174 | "coming. Good luck.\n" 175 | 176 | ,/*......................................*/ 177 | "Our competitors, the Alliance for a\n" 178 | "Utopian Future, are getting a little\n" 179 | "too good to ignore. We're nuking them.\n" 180 | "However, we really don't want to kill\n" 181 | "anyone, so get them out of there\n" 182 | "before our missiles get there.\n" 183 | "It's just a matter of business, you\n" 184 | "understand..." 185 | 186 | ,/*......................................*/ 187 | "The AUF apparently had a backup strike\n" 188 | "force that we didn't know about. All\n" 189 | "our people are alerted, but there are\n" 190 | "a number of people on the lower levels\n" 191 | "that won't be able to get out in time.\n" 192 | "Get them quick! Meet you at Basepoint\n" 193 | "Delta!\n" 194 | 195 | }; 196 | 197 | -------------------------------------------------------------------------------- /JM_SB.C: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | /* 20 | ** jm_sb.c 21 | ** Jason's Music routines for games 22 | ** SoundBlaster Stuff 23 | ** v1.0d4 24 | */ 25 | 26 | #include 27 | 28 | #include "JM_SB.H" 29 | 30 | //#pragma warn -pia // Because I use if (x = y) alot... 31 | 32 | // Macros for SoundBlaster stuff 33 | #define sbOut(n,b) outportb((n) + sbLocation,b) 34 | #define sbIn(n) inportb((n) + sbLocation) 35 | #define sbWriteDelay() while (sbIn(sbWriteStat) & 0x80); 36 | #define sbReadDelay() while (sbIn(sbDataAvail) & 0x80); 37 | 38 | // 39 | // Stuff I need 40 | // 41 | static boolean sbSamplePlaying = false; 42 | static byte sbOldIntMask = -1; 43 | static byte *sbNextSegPtr; 44 | static int sbLocation = -1,sbInterrupt = 7,sbIntVec = 0xf, 45 | sbIntVectors[] = {-1,-1,0xa,0xb,-1,0xd,-1,0xf}; 46 | static longword sbNextSegLen; 47 | static SampledSound *sbSamples; 48 | #if 0 49 | static void interrupt (*sbOldIntHand)(void); 50 | #endif 51 | 52 | byte * jmData; 53 | int jmDataLength; 54 | int jmDataFreq; 55 | float jmDataTime; 56 | 57 | // 58 | // jmDelay(usec) - Delays for usec micro-seconds 59 | // 60 | static void 61 | jmDelay(int usec) 62 | { 63 | // DEBUG - use real timing routines 64 | int i; 65 | 66 | while (usec--) 67 | for (i = 0;i < 1000;i++) 68 | ; 69 | } 70 | 71 | // 72 | // SoundBlaster code 73 | // 74 | 75 | // 76 | // Plays a chunk of sampled sound 77 | // 78 | #if 0 79 | static longword 80 | jmPlaySeg(byte *data,longword length) 81 | { 82 | unsigned datapage; 83 | longword dataofs,uselen; 84 | 85 | uselen = length; 86 | datapage = FP_SEG(data) >> 12; 87 | dataofs = ( (FP_SEG(data)&0xfff)<<4 ) + FP_OFF(data); 88 | if (dataofs>=0x10000) 89 | { 90 | datapage++; 91 | dataofs-=0x10000; 92 | } 93 | 94 | if (dataofs + uselen > 0x10000) 95 | uselen = 0x10000 - dataofs; 96 | 97 | uselen--; // DEBUG 98 | 99 | // Program the DMA controller 100 | outportb(0x0a,5); // Mask off channel 1 DMA 101 | outportb(0x0c,0); // Clear byte ptr F/F to lower byte 102 | outportb(0x0b,0x49); // Set transfer mode for D/A conv 103 | outportb(0x02,(byte)dataofs); // Give LSB of address 104 | outportb(0x02,(byte)(dataofs >> 8)); // Give MSB of address 105 | outportb(0x83,(byte)datapage); // Give page of address 106 | outportb(0x03,(byte)uselen); // Give LSB of length 107 | outportb(0x03,(byte)(uselen >> 8)); // Give MSB of length 108 | outportb(0x0a,1); // Turn on channel 1 DMA 109 | 110 | // Start playing the thing 111 | sbWriteDelay(); 112 | sbOut(sbWriteCmd,0x14); 113 | sbWriteDelay(); 114 | sbOut(sbWriteData,(byte)uselen); 115 | sbWriteDelay(); 116 | sbOut(sbWriteData,(byte)(uselen >> 8)); 117 | 118 | return(++uselen); 119 | } 120 | #endif 121 | 122 | // 123 | // Services the SoundBlaster DMA interrupt 124 | // 125 | #if 0 126 | void interrupt 127 | jmSBService(void) 128 | { 129 | longword used; 130 | 131 | sbIn(sbDataAvail); 132 | outportb(0x20,0x20); 133 | 134 | if (sbNextSegPtr) 135 | { 136 | used = jmPlaySeg(sbNextSegPtr,sbNextSegLen); 137 | if (sbNextSegLen <= used) 138 | sbNextSegPtr = nil; 139 | else 140 | { 141 | sbNextSegPtr += used; 142 | sbNextSegLen -= used; 143 | } 144 | } 145 | else 146 | jmStopSample(); 147 | } 148 | #endif 149 | 150 | // 151 | // Plays a sampled sound. Returns immediately and uses DMA to play the sound 152 | // 153 | void 154 | jmPlaySample(int sound) 155 | { 156 | byte *data, 157 | timevalue; 158 | longword used; 159 | SampledSound sample; 160 | 161 | jmStopSample(); 162 | 163 | sample = sbSamples[--sound]; 164 | 165 | #if 0 166 | data = ((byte *)sbSamples) + sample.offset; 167 | timevalue = 256 - (1000000 / sample.hertz); 168 | 169 | // printf("sample #%d ",sound); 170 | // printf("%ld bytes, %ldHz, tc=%d\n",sample.length,sample.hertz,timevalue); 171 | 172 | // printf("setting time constant\n"); 173 | // Set the SoundBlaster DAC time constant 174 | sbWriteDelay(); 175 | sbOut(sbWriteCmd,0x40); 176 | sbWriteDelay(); 177 | sbOut(sbWriteData,timevalue); 178 | 179 | used = jmPlaySeg(data,sample.length); 180 | if (sample.length <= used) 181 | sbNextSegPtr = nil; 182 | else 183 | { 184 | sbNextSegPtr = data + used; 185 | sbNextSegLen = sample.length - used; 186 | } 187 | 188 | // printf("enabling SB irq #%d\n",sbInterrupt); 189 | // Save old interrupt status and unmask ours 190 | sbOldIntMask = inportb(0x21); 191 | outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt)); 192 | 193 | // printf("enabling DSP DMA request\n"); 194 | sbWriteDelay(); 195 | sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled 196 | #endif 197 | jmData = ((byte *)sbSamples) + sample.offset; 198 | jmDataLength = sample.length; 199 | jmDataFreq = sample.hertz; 200 | jmDataTime = 0; 201 | 202 | // printf("sound should be playing\n"); 203 | sbSamplePlaying = true; 204 | } 205 | 206 | // 207 | // Stops any active sampled sound and causes DMA to cease 208 | // 209 | void 210 | jmStopSample(void) 211 | { 212 | extern byte SndPriority; 213 | #if 0 214 | byte is; 215 | 216 | if (sbSamplePlaying) 217 | { 218 | // printf("turning off DSP DMA\n"); 219 | sbWriteDelay(); 220 | sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA 221 | 222 | // printf("restoring interrupt\n"); 223 | is = inportb(0x21); // Restore interrupt mask bit 224 | if (sbOldIntMask & (1 << sbInterrupt)) 225 | is |= (1 << sbInterrupt); 226 | else 227 | is &= ~(1 << sbInterrupt); 228 | outportb(0x21,is); 229 | 230 | 231 | sbSamplePlaying = false; 232 | SndPriority = 0; // JC: hack for playsound 233 | } 234 | #endif 235 | if (sbSamplePlaying) 236 | { 237 | jmData = 0; 238 | jmDataLength = 0; 239 | jmDataFreq = 0; 240 | sbSamplePlaying = false; 241 | SndPriority = 0; 242 | } 243 | } 244 | // 245 | // Checks to see if a SoundBlaster resides at a particular I/O location 246 | // 247 | #if 0 248 | static boolean 249 | jmCheckSB(int port) 250 | { 251 | int i; 252 | 253 | sbLocation = port << 4; // Initialize stuff for later use 254 | 255 | sbOut(sbReset,true); // Reset the SoundBlaster DSP 256 | jmDelay(4); // Wait 4usec 257 | sbOut(sbReset,false); // Turn off sb DSP reset 258 | jmDelay(100); // Wait 100usec 259 | for (i = 0;i < 100;i++) 260 | { 261 | if (sbIn(sbDataAvail) & 0x80) // If data is available... 262 | { 263 | if (sbIn(sbReadData) == 0xaa) // If it matches correct value 264 | return(true); 265 | else 266 | { 267 | sbLocation = -1; // Otherwise not a SoundBlaster 268 | return(false); 269 | } 270 | } 271 | } 272 | sbLocation = -1; // Retry count exceeded - fail 273 | return(false); 274 | } 275 | #endif 276 | 277 | // 278 | // Checks to see if a SoundBlaster is in the system. If the port passed is 279 | // -1, then it scans through all possible I/O locations. If the port 280 | // passed is 0, then it uses the default (2). If the port is >0, then 281 | // it just passes it directly to jmCheckSB() 282 | // 283 | boolean 284 | jmDetectSoundBlaster(int port) 285 | { 286 | #if 0 287 | int i; 288 | 289 | if (port == 0) // If user specifies default address, use 2 290 | port = 2; 291 | if (port == -1) 292 | { 293 | for (i = 1;i <= 6;i++) // Scan through possible SB locations 294 | { 295 | if (jmCheckSB(i)) // If found at this address, 296 | return(true); // return success 297 | } 298 | return(false); // All addresses failed, return failure 299 | } 300 | else 301 | return(jmCheckSB(port)); // User specified address or default 302 | #endif 303 | return 1; 304 | } 305 | 306 | // 307 | // Sets the interrupt number that my code expects the SoundBlaster to use 308 | // 309 | #if 0 310 | void 311 | jmSetSBInterrupt(int num) 312 | { 313 | sbInterrupt = num; 314 | sbIntVec = sbIntVectors[sbInterrupt]; 315 | } 316 | #endif 317 | 318 | void 319 | jmStartSB(void) 320 | { 321 | #if 0 322 | // printf("setting interrupt #0x%02x handler\n",sbIntVec); 323 | sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler 324 | setvect(sbIntVec,jmSBService); // Set mine 325 | 326 | // printf("setting DSP modes\n"); 327 | sbWriteDelay(); 328 | sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker 329 | #endif 330 | } 331 | 332 | void 333 | jmShutSB(void) 334 | { 335 | jmStopSample(); 336 | 337 | #if 0 338 | // printf("restoring interrupt vector\n"); 339 | setvect(sbIntVec,sbOldIntHand); // Set vector back 340 | #endif 341 | } 342 | 343 | boolean 344 | jmSamplePlaying(void) 345 | { 346 | return(sbSamplePlaying); 347 | } 348 | 349 | void 350 | jmSetSamplePtr(SampledSound *s) 351 | { 352 | sbSamples = s; 353 | } 354 | -------------------------------------------------------------------------------- /HOVERDEF.H: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /* Hovertank 3-D Source Code 5 | * Copyright (C) 1993-2014 Flat Rock Software 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | */ 21 | 22 | /* 23 | ============================================================================= 24 | 25 | HOVERTANK MAIN 26 | 27 | ============================================================================= 28 | */ 29 | #include "IDLIB.H" 30 | 31 | #define OLDDRAW 32 | 33 | //#define PROFILE 34 | 35 | #ifndef PROFILE 36 | #define ADAPTIVE 37 | #endif 38 | 39 | 40 | //#define TESTCASE 41 | 42 | #define MAXTICS 8 43 | 44 | #define NUMLEVELS 20 45 | 46 | 47 | typedef struct { short width; 48 | short height; 49 | short planes; 50 | short screenx; 51 | short screeny; 52 | short screenw; 53 | short screenh; 54 | unsigned short planesize; 55 | } LevelDef; 56 | 57 | LevelDef extern *levelheader; 58 | 59 | 60 | /* 61 | ============================================================================= 62 | 63 | REFRESH 64 | 65 | ============================================================================= 66 | */ 67 | 68 | #define VIEWX 0 // corner of view window 69 | #define VIEWY 0 70 | #define VIEWWIDTH (40*8) // size of view window 71 | #define VIEWHEIGHT (18*8) 72 | #define VIEWXH (VIEWX+VIEWWIDTH-1) 73 | #define VIEWYH (VIEWY+VIEWHEIGHT-1) 74 | 75 | #define CENTERX (VIEWX+VIEWWIDTH/2) // middle of view window 76 | #define CENTERY (VIEWY+VIEWHEIGHT/2) 77 | 78 | #define STATUSLINES (9*8) // dash board 79 | 80 | #define GLOBAL1 (1l<<16) 81 | #define TILEGLOBAL GLOBAL1 82 | #define TILESHIFT 16 83 | 84 | #define MINDIST (2*GLOBAL1/5) 85 | #define FOCALLENGTH (TILEGLOBAL) // in global coordinates 86 | 87 | #define ANGLES 360 // must be divisable by 4 88 | 89 | #define MAPSIZE 64 // maps are 64*64 max 90 | #define MAXOBJECTS 100 // max number of tanks, etc / map 91 | 92 | // 93 | // 1 sign bit 94 | // 15 bits units 95 | // 16 bits fractional 96 | // 97 | #define SIGNBIT error//0x80000000l 98 | 99 | typedef int32_t fixed; 100 | 101 | #define NORTH 0 102 | #define EAST 1 103 | #define SOUTH 2 104 | #define WEST 3 105 | 106 | /* 107 | ============================================================================= 108 | 109 | DASH INSTRUMENTS 110 | 111 | ============================================================================= 112 | */ 113 | 114 | #define TIMESECX 3 115 | #define TIMESECY 54 116 | #define TIMEMINX 1 117 | #define TIMEMINY 54 118 | 119 | #define RADARX 284 // center of radar 120 | #define RADARY 36 121 | #define RADARSIZE 26 // each way 122 | #define RADARRANGE (TILEGLOBAL*18) // each way 123 | #define RADARSCALE (RADARRANGE/RADARSIZE) 124 | 125 | /* 126 | ============================================================================= 127 | 128 | HOVMAIN 129 | 130 | ============================================================================= 131 | */ 132 | 133 | extern int tedlevel; 134 | extern memptr scalesegs[NUMPICS]; 135 | 136 | //========================================================================== 137 | 138 | int CheckKeys(void); 139 | void CachePic (int picnum); 140 | void LoadLevel(void); 141 | void CacheDrawPic(int picnum); 142 | int SoundPlaying (void); 143 | 144 | /* 145 | ============================================================================= 146 | 147 | HOVDRAW 148 | 149 | ============================================================================= 150 | */ 151 | 152 | void FollowWalls (void); 153 | 154 | /* 155 | ============================================================================= 156 | 157 | HOVDRAW 158 | 159 | ============================================================================= 160 | */ 161 | 162 | 163 | typedef struct {int x,y;} tilept; 164 | typedef struct {fixed x,y;} globpt; 165 | 166 | typedef struct 167 | { 168 | int x1,x2,leftclip,rightclip;// first pixel of wall (may not be visable) 169 | unsigned height1,height2,color; 170 | int wx0,wz0,wx1,wz1; 171 | } walltype; 172 | 173 | #define MAXWALLS 100 174 | #define DANGERHIGH 90 175 | #define DANGERLOW 10 176 | 177 | #define MIDWALL (MAXWALLS/2) 178 | 179 | 180 | //========================================================================== 181 | 182 | #if 0 183 | extern tilept tile,lasttile,focal,left,mid,right; 184 | 185 | extern globpt edge,view; 186 | 187 | extern unsigned screenloc[3]; 188 | 189 | extern int screenpage,tics; 190 | 191 | extern long lasttimecount; 192 | #define SHIFTFRAMES 256 193 | extern int yshift[SHIFTFRAMES]; // screen sliding variables 194 | 195 | extern int firstangle,lastangle; 196 | 197 | extern fixed prestep; 198 | 199 | extern int traceclip,tracetop; 200 | 201 | extern fixed sintable[ANGLES+ANGLES/4],*costable; 202 | 203 | extern fixed viewx,viewy,viewsin,viewcos; // the focal point 204 | extern int viewangle; 205 | 206 | extern fixed scale,scaleglobal; 207 | extern unsigned slideofs; 208 | 209 | extern int zbuffer[VIEWXH+1]; 210 | 211 | extern walltype walls[MAXWALLS],*leftwall,*rightwall; 212 | #else 213 | extern tilept tile,focal,right; 214 | 215 | extern unsigned screenloc[3]; 216 | 217 | extern int screenpage,tics; 218 | 219 | extern int32_t lasttimecount; 220 | 221 | extern fixed sintable[ANGLES+ANGLES/4],*costable; 222 | 223 | extern fixed viewx,viewy,viewsin,viewcos; // the focal point 224 | 225 | extern int zbuffer[VIEWXH+1]; 226 | 227 | extern walltype walls[MAXWALLS],*rightwall; 228 | #endif 229 | 230 | 231 | //========================================================================== 232 | 233 | #if 0 234 | void DrawLine (int xl, int xh, int y,int color); 235 | void DrawWall (walltype *wallptr); 236 | void TraceRay (unsigned angle); 237 | fixed FixedByFrac (fixed a, fixed b); 238 | fixed FixedAdd (fixed a, fixed b); 239 | void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight); 240 | fixed TransformX (fixed gx, fixed gy); 241 | void StartView (void); 242 | void FinishView (void); 243 | int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max); 244 | void ForwardTrace (void); 245 | int FinishWall (void); 246 | int TurnClockwise (void); 247 | int TurnCounterClockwise (void); 248 | void FollowWall (void); 249 | 250 | void NewScene (void); 251 | void BuildTables (void); 252 | #else 253 | 254 | fixed FixedByFrac (fixed a, fixed b); 255 | void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight); 256 | fixed TransformX (fixed gx, fixed gy); 257 | void StartView (void); 258 | void FinishView (void); 259 | 260 | void BuildTables (void); 261 | #endif 262 | 263 | 264 | /* 265 | ============================================================================= 266 | 267 | HOVLOOP 268 | 269 | ============================================================================= 270 | */ 271 | 272 | // 273 | // temp stuff 274 | // 275 | extern int statx,staty; 276 | 277 | 278 | extern unsigned tilemap[MAPSIZE][MAPSIZE]; 279 | 280 | typedef enum 281 | {nothing,playerobj,refugeeobj,droneobj,tankobj,mutantobj,warpobj, 282 | pshotobj,pbigshotobj,mshotobj,inertobj,shieldobj} classtype; 283 | 284 | typedef struct 285 | { 286 | int active; 287 | classtype _class; 288 | fixed x,y; 289 | fixed viewx,viewy; // x,y in view coordinate space (NOT pixels!) 290 | int angle; 291 | int hitpoints; 292 | int radarx,radary,radarcolor; 293 | int32_t speed; 294 | unsigned size; // global radius for hit rect calculation 295 | fixed xl,xh,yl,yh; // hit rectangle 296 | int ticcount; 297 | int shapenum,stage; 298 | union { 299 | int temp1; 300 | void* temp1ptr; 301 | }; 302 | int temp2; 303 | dirtype dir; 304 | void (*think)(); 305 | } objtype; 306 | 307 | typedef struct {int min,sec;} timetype; 308 | extern timetype timestruct; 309 | 310 | extern ControlStruct c; 311 | 312 | extern int guncount,bordertime; 313 | 314 | extern fixed warpx,warpy; // where to spawn warp gate 315 | extern fixed xmove,ymove; 316 | 317 | 318 | extern int godmode,singlestep,leveldone,resetgame; 319 | extern int numrefugees,totalrefugees,savedcount,killedcount; 320 | 321 | extern objtype objlist[MAXOBJECTS],obon,*_new,*obj,*lastobj,*check; 322 | 323 | void FindFreeObj (void); 324 | void CalcBoundsNew (void); 325 | 326 | void CalcBounds (void); 327 | void TransformObon (void); 328 | 329 | void PlayerThink (void); 330 | 331 | void PlayLoop (void); 332 | void PlayGame (void); 333 | 334 | void ClipMove (void); 335 | 336 | void StartLevel (unsigned short *plane1); 337 | 338 | /* 339 | ============================================================================= 340 | 341 | HOVSCALE 342 | 343 | ============================================================================= 344 | */ 345 | 346 | extern unsigned scaleblockwidth, 347 | scaleblockheight, 348 | scaleblockdest; 349 | 350 | int SC_ScaleShape (int x,int y,unsigned scale, memptr shape); 351 | void SC_Setup (void); 352 | void SC_MakeShape (memptr src,int width,int height, memptr *shapeseg); 353 | 354 | /* 355 | ============================================================================= 356 | 357 | HOVACTS 358 | 359 | ============================================================================= 360 | */ 361 | 362 | void DamagePlayer (void); 363 | void HealPlayer (void); 364 | void Thrust (void); 365 | void SpawnShield (fixed gx, fixed gy); 366 | 367 | 368 | 369 | // =========================================================== 370 | -------------------------------------------------------------------------------- /IDLIB.H: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #define EXTENSION "HOV" 20 | 21 | #include "GRAPHHOV.H" 22 | #include "SNDSHOV.H" 23 | 24 | #include 25 | 26 | #ifndef __jm__ 27 | typedef uint16_t boolean; 28 | typedef uint8_t byte; 29 | #endif 30 | 31 | #define SIGN(x) ((x)>0?1:-1) 32 | #define ABS(x) ((int)(x)>0?(x):-(x)) 33 | #define LABS(x) ((int32_t)(x)>0?(x):-(x)) 34 | 35 | 36 | 37 | 38 | int extern level,bestlevel; 39 | 40 | /* 41 | ============================================================================ 42 | 43 | MEMORY MANAGER 44 | 45 | ============================================================================ 46 | */ 47 | 48 | #include "MEMMGR.H" 49 | 50 | /* 51 | ============================================================================ 52 | 53 | ** Sound routines 54 | ** Ties into INT 8, with a timer tic at 8 * normal rate (144/sec) 55 | 56 | ============================================================================ 57 | */ 58 | 59 | //typedef enum {off,spkr,adlib} soundtype; 60 | 61 | #pragma pack(push, 1) 62 | typedef struct {unsigned short start; 63 | byte priority; 64 | byte samplerate; 65 | char name[12];} spksndtype; 66 | #pragma pack(pop) 67 | 68 | #if 0 69 | typedef struct {char id[4]; 70 | unsigned filelength; 71 | unsigned filler[5]; 72 | spksndtype sounds[63]; 73 | unsigned freqdata[];} SPKRtable; 74 | #endif 75 | 76 | 77 | int extern soundmode; 78 | int extern soundblaster; 79 | 80 | //extern unsigned timerspeed; 81 | //extern int dontplay; 82 | //extern unsigned inttime; 83 | //extern long timecount; 84 | 85 | //extern unsigned int8hook; // address of function to call every tic 86 | 87 | extern memptr soundseg; 88 | //extern unsigned sndptr; 89 | 90 | //void StartupSound (void); 91 | //void CallTimer (void); 92 | //void ShutdownSound (void); 93 | void PlaySound (int sound); 94 | //void PauseSound (void); 95 | //void ContinueSound (void); 96 | //void StopSound (void); 97 | //void WaitEndSound (void); 98 | 99 | 100 | /* 101 | ============================================================================ 102 | 103 | ** Control routines 104 | ** Ties into INT 9 to intercept all key presses, but passes on to BIOS 105 | ** The control panel handles all this stuff! 106 | 107 | ============================================================================ 108 | */ 109 | 110 | typedef enum {north,northeast,east,southeast,south,southwest,west, 111 | northwest,nodir} dirtype; 112 | 113 | typedef struct {dirtype dir; 114 | boolean button1,button2;} ControlStruct; 115 | 116 | typedef enum {keyboard,mouse,joystick1,joystick2,demo} inputtype; 117 | 118 | inputtype extern playermode[3]; 119 | //extern char keydown[128]; 120 | char * GetKeyDown(void); 121 | #define keydown (GetKeyDown()) 122 | int extern JoyXlow[3], 123 | JoyXhigh[3], 124 | JoyYlow [3], 125 | JoyYhigh [3]; // 1&2 are used, 0 is just space 126 | 127 | char extern key[8], keyB1, keyB2; // scan codes for key control 128 | 129 | void LoadCtrls (void); 130 | void SaveCtrls (void); 131 | 132 | void ReadJoystick (int joynum,int *xcount,int *ycount); 133 | 134 | void CalibrateJoy (int joynum); 135 | void calibratekeys (void); 136 | 137 | ControlStruct ControlKBD (void); 138 | ControlStruct ControlJoystick (int joynum); 139 | ControlStruct ControlPlayer (int player); 140 | 141 | void ClearKeys (void); 142 | void Ack(void); 143 | 144 | int NoBiosKey(int parm); 145 | //extern int NBKscan, NBKascii; 146 | int GetNBKscan(); 147 | int GetNBKascii(); 148 | #define NBKscan (GetNBKscan()) 149 | #define NBKascii (GetNBKascii()) 150 | 151 | /* 152 | =========================================================================== 153 | 154 | ** Miscellaneous library routines 155 | 156 | =========================================================================== 157 | */ 158 | 159 | typedef struct 160 | { 161 | unsigned short bit0,bit1; // 0-255 is a character, > is a pointer to a node 162 | } huffnode; 163 | 164 | #define StopDrive() {} //void StopDrive (void); 165 | 166 | void BloadinMM (char *filename,memptr *spot); 167 | 168 | void OptimizeNodes (huffnode *table); 169 | 170 | void HuffExpand (unsigned char *source, unsigned char *dest, 171 | int32_t length,huffnode *hufftable); 172 | 173 | void RLEWExpand (unsigned short *source, unsigned short *dest); 174 | 175 | //void RLEBExpand (unsigned char far *source, unsigned char far *dest); 176 | 177 | //void RLEExpand (char far *surce,char far *dest,long length); 178 | //unsigned RLECompress (char far *source, unsigned Length, char far *dest); 179 | 180 | void InitRnd (boolean randomize); /* ASM */ 181 | int Rnd (int max); /* ASM */ 182 | void InitRndT (boolean randomize); /* ASM */ 183 | int RndT (void); /* ASM */ 184 | 185 | /* 186 | ============================================================================ 187 | 188 | ** Graphic routines 189 | ** Edge graphic file not needed 190 | ** 191 | ** Many of these #defines are duplicates as EQUs in EDGEASM, and must be == 192 | 193 | ============================================================================ 194 | */ 195 | 196 | #define SCREENWIDTH 40 197 | 198 | //void SetScreenMode (grtype mode); // sets graphic mode 199 | void WaitVBL (int num); // waits for no sync, then sync 200 | 201 | //void LoadPage(char *filename,unsigned dest); 202 | 203 | //void EGAPlane (int plane); // read / write from plane 0-4 204 | void EGASplitScreen (int linenum); // splits a 200 line screen 205 | //void CRTCstart (unsigned start); // set crtc high/low registers 206 | //void EGAVirtualScreen (int width); // sets screen width 207 | void ColorBorder (int color); // sets overscan color 208 | 209 | //cardtype VideoID (void); // returns the display adapter installed 210 | 211 | //void SetDefaultColors(void); // full bright palete 212 | void FadeOut (void); // EGA 16 color palette fade 213 | void FadeIn (void); 214 | void FadeUp (void); 215 | void FadeDown (void); 216 | 217 | //void XorBar(int xl,int yl,int width,int height); 218 | void Bar (int xl,int yl,int width,int height,int fill); 219 | 220 | /* 221 | ============================================================================ 222 | 223 | IGRAB Graphic file routines 224 | 225 | Based on number reported in GRAPHEXT.H header file! 226 | 227 | ============================================================================ 228 | */ 229 | 230 | typedef struct 231 | { 232 | int16_t width,height; 233 | } pictype; 234 | 235 | extern unsigned screenofs; // adjustment for panning and buffers 236 | 237 | unsigned extern linewidth; 238 | 239 | // 240 | // cachable locations 241 | // 242 | 243 | extern memptr grsegs[NUMCHUNKS]; 244 | extern char needgr[NUMCHUNKS]; // for caching 245 | 246 | #if NUMPICS>0 247 | extern pictype pictable[NUMPICS]; 248 | #endif 249 | 250 | // 251 | // proportional font stuff 252 | // 253 | #if NUMFONT+NUMFONTM>0 254 | extern unsigned fontcolor,pdrawmode; 255 | extern unsigned px,py; 256 | extern unsigned pxl,pxh,pyl,pyh; 257 | //extern fontstruct * fontseg; 258 | 259 | void DrawPchar (int Char); 260 | void DrawMPchar (int Char); 261 | #endif 262 | 263 | void SetScreen(int crtc, int pel); 264 | 265 | // 266 | // base drawing routines, x in bytes, y in lines 267 | // 268 | 269 | void XPlot (int x, int y, int color); 270 | void Block (int x, int y, int color); 271 | void DrawLine (int xl, int xh, int y,int color); 272 | void DrawRect (int x, int y, int width, int height, int color); 273 | void DrawLineZ (int xl, int xh, int y, int zl, int zh,int color); 274 | void DrawChar (int x, int y, int picnum); 275 | //void MaskChar (int x, int y, int picnum); 276 | //void CopyChar (int x, int y); 277 | void DrawPic (int x, int y, int picnum); 278 | void DrawShape(int x,int y,unsigned scale, memptr shapeptr); 279 | void DrawScaledShape(int sxl, int yl, int sxh, int yh, int shapexl, int shapexh, memptr shapeptr); 280 | void SetLineWidth (int width); 281 | //void DrawSprite (int xcoord, int ycoord, int spritenum); 282 | //void DrawSpriteT (unsigned wide,unsigned height,unsigned source, 283 | // unsigned dest, unsigned plsize); 284 | 285 | //void SetBitMask(unsigned int mask); 286 | //void ScaleLine (int pixels, void *scaleptr, void *picptr, int screen); 287 | 288 | void CopyEGA(int wide, int height, int source, int dest); 289 | 290 | /* 291 | ============================================================================ 292 | 293 | ** Mid level graphic routines 294 | 295 | ============================================================================ 296 | */ 297 | 298 | #if 0 299 | int extern sx,sy,leftedge, screencenterx ,screencentery, segoffset; 300 | #else 301 | int extern sx,sy,leftedge,screencenterx ,screencentery; 302 | #endif 303 | 304 | //int Get (void); 305 | int Input(char *string,int max); 306 | unsigned InputInt(void); 307 | void Print (const char *str); 308 | //void Printxy(int x,int y,char *string); 309 | //void PrintC(char *string); 310 | //void PrintHexB(unsigned char value); 311 | //void PrintHex(unsigned value); 312 | //void PrintBin(unsigned value); 313 | //void PrintInt (int val); 314 | //void PrintLong (long val); 315 | 316 | int PGet (void); 317 | void PPrint (const char *str); 318 | void CPPrint (const char *str); 319 | void PPrintInt (int val); 320 | void PPrintUnsigned (unsigned val); 321 | 322 | void DrawWindow (int xl, int yl, int xh, int yh); 323 | void EraseWindow (void); 324 | //void CharBar (int xl,int yl, int xh, int yh, int ch); 325 | void CenterWindow (int width, int height); 326 | void ExpWin (int width, int height); 327 | void ExpWinH (int width, int height); 328 | void ExpWinV (int width, int height); 329 | //void DrawFrame(int x1,int y1,int x2,int y2,int type); 330 | 331 | 332 | /* 333 | ============================================================================ 334 | 335 | ** Game level routines 336 | 337 | ============================================================================ 338 | */ 339 | 340 | int32_t extern score,highscore; 341 | 342 | /* 343 | ============================================================================ 344 | 345 | ** Needed non library routines 346 | 347 | ============================================================================ 348 | */ 349 | 350 | void Quit (const char *); 351 | 352 | /* 353 | ============================================================================ 354 | 355 | ** New stuff 356 | 357 | ============================================================================ 358 | */ 359 | 360 | #include 361 | #include 362 | #include 363 | #include 364 | #include 365 | #include 366 | #include 367 | #include "matrix.h" 368 | 369 | #include "JM_SB.H" 370 | 371 | #define itoa(value, str, base) {assert(base == 10); sprintf(str,"%d",value);} 372 | #define ltoa(value, str, base) {assert(base == 10); sprintf(str,"%d",value);} 373 | 374 | typedef struct 375 | { 376 | uint32_t width; 377 | uint32_t height; 378 | uint32_t texture; 379 | } gltexture; 380 | 381 | extern SDL_Window * window; 382 | 383 | int32_t filelength(FILE * handle); 384 | 385 | extern matrix4x4_t matProj2D; 386 | 387 | void IDLIBC_SDL_Init(); 388 | 389 | unsigned int GetColor(int i); 390 | 391 | extern int video_screenofs_x, video_screenofs_y; 392 | void SetScreenOfs(void); 393 | 394 | void UseTextureShader(float * matrix, float * vertices, int blend, unsigned int texture, float * texcoord); 395 | 396 | memptr CreateTexture(int width, int height, const memptr planes, unsigned char background); 397 | 398 | void CreateFont(); 399 | 400 | void VideoSync(void); 401 | 402 | #define timecount (SDL_GetTicks()*140/1000) 403 | 404 | int *UpdateIntTime(); 405 | #define inttime (*(UpdateIntTime())) 406 | 407 | 408 | 409 | void EnableZ(int x, int y, int width, int height, float viewx, float viewz, float viewangle); 410 | void DisableZ(); 411 | void DrawPlaneZ(float width, float length, float y, int color); 412 | void DrawWallZ(float x0, float z0, float x1, float z1, int color); 413 | void DrawShapeZ(float x, float z, memptr shapeseg); 414 | 415 | 416 | // Enables the PC speaker at the given frequency. The argument _frequency should be given in Hertz units. 417 | void sound(int _frequency); 418 | // Disable the PC speaker. 419 | void nosound(void); 420 | -------------------------------------------------------------------------------- /IDLIBC_SHADERS.C: -------------------------------------------------------------------------------- 1 | 2 | #include "IDLIB.H" 3 | #include "IDLIB_SDL.H" 4 | 5 | void glActiveTexture(int x); 6 | 7 | #define glActiveTexture _glActiveTexture 8 | 9 | // to use macro convenience 10 | #define PFNglCreateShaderPROC PFNGLCREATESHADERPROC 11 | #define PFNglShaderSourcePROC PFNGLSHADERSOURCEPROC 12 | #define PFNglCompileShaderPROC PFNGLCOMPILESHADERPROC 13 | #define PFNglGetShaderivPROC PFNGLGETSHADERIVPROC 14 | #define PFNglGetShaderInfoLogPROC PFNGLGETSHADERINFOLOGPROC 15 | #define PFNglCreateProgramPROC PFNGLCREATEPROGRAMPROC 16 | #define PFNglAttachShaderPROC PFNGLATTACHSHADERPROC 17 | #define PFNglLinkProgramPROC PFNGLLINKPROGRAMPROC 18 | #define PFNglGetProgramivPROC PFNGLGETPROGRAMIVPROC 19 | #define PFNglGetProgramInfoLogPROC PFNGLGETPROGRAMINFOLOGPROC 20 | #define PFNglUseProgramPROC PFNGLUSEPROGRAMPROC 21 | #define PFNglGetUniformLocationPROC PFNGLGETUNIFORMLOCATIONPROC 22 | #define PFNglGetAttribLocationPROC PFNGLGETATTRIBLOCATIONPROC 23 | #define PFNglUniformMatrix4fvPROC PFNGLUNIFORMMATRIX4FVPROC 24 | #define PFNglVertexAttribPointerPROC PFNGLVERTEXATTRIBPOINTERPROC 25 | #define PFNglEnableVertexAttribArrayPROC PFNGLENABLEVERTEXATTRIBARRAYPROC 26 | #define PFNglUniform1fPROC PFNGLUNIFORM1FPROC 27 | #define PFNglUniform4fPROC PFNGLUNIFORM4FPROC 28 | #define PFNglUniform1iPROC PFNGLUNIFORM1IPROC 29 | #define PFNglActiveTexturePROC PFNGLACTIVETEXTUREPROC 30 | 31 | // use the convenient macros 32 | GLDEFINE(glCreateProgram); 33 | GLDEFINE(glCreateShader); 34 | GLDEFINE(glCompileShader); 35 | GLDEFINE(glGetShaderiv); 36 | GLDEFINE(glGetShaderInfoLog); 37 | GLDEFINE(glShaderSource); 38 | GLDEFINE(glAttachShader); 39 | GLDEFINE(glLinkProgram); 40 | GLDEFINE(glGetProgramiv); 41 | GLDEFINE(glGetProgramInfoLog); 42 | GLDEFINE(glUseProgram); 43 | GLDEFINE(glGetUniformLocation); 44 | GLDEFINE(glGetAttribLocation); 45 | GLDEFINE(glUniformMatrix4fv); 46 | GLDEFINE(glVertexAttribPointer); 47 | GLDEFINE(glEnableVertexAttribArray); 48 | GLDEFINE(glUniform1f); 49 | GLDEFINE(glUniform4f); 50 | GLDEFINE(glUniform1i); 51 | _GLDEFINE(glActiveTexture); 52 | 53 | typedef struct 54 | { 55 | GLuint vertexShader; 56 | GLuint fragmentShader; 57 | GLuint program; 58 | GLuint matrix; 59 | GLuint position; 60 | } common_shader_t; 61 | 62 | int CreateCommonShader(common_shader_t * shader, const GLchar * vertexShaderSource, const GLchar * fragmentShaderSource); 63 | void UseCommonShader(const common_shader_t * shader, const float * matrix, const float * vertices); 64 | 65 | void CreateColorShader(); 66 | void CreateTextureShader(); 67 | void CreateFontShader(); 68 | void CreateFadeShader(); 69 | 70 | 71 | 72 | 73 | 74 | void SHADERS_Init(void) 75 | { 76 | GLGETPROC(glCreateProgram); 77 | GLGETPROC(glCreateShader); 78 | GLGETPROC(glCompileShader); 79 | GLGETPROC(glGetShaderiv); 80 | GLGETPROC(glGetShaderInfoLog); 81 | GLGETPROC(glShaderSource); 82 | GLGETPROC(glAttachShader); 83 | GLGETPROC(glLinkProgram); 84 | GLGETPROC(glGetProgramiv); 85 | GLGETPROC(glGetProgramInfoLog); 86 | GLGETPROC(glUseProgram); 87 | GLGETPROC(glGetUniformLocation); 88 | GLGETPROC(glGetAttribLocation); 89 | GLGETPROC(glUniformMatrix4fv); 90 | GLGETPROC(glVertexAttribPointer); 91 | GLGETPROC(glEnableVertexAttribArray); 92 | GLGETPROC(glUniform1f); 93 | GLGETPROC(glUniform4f); 94 | GLGETPROC(glUniform1i); 95 | _GLGETPROC(glActiveTexture); 96 | 97 | CreateColorShader(); 98 | CreateTextureShader(); 99 | CreateFontShader(); 100 | CreateFadeShader(); 101 | } 102 | 103 | 104 | 105 | int CreateCommonShader(common_shader_t * shader, const GLchar * vertexShaderSource, const GLchar * fragmentShaderSource) 106 | { 107 | GLint logLength; 108 | 109 | shader->vertexShader = glCreateShader(GL_VERTEX_SHADER); 110 | glShaderSource(shader->vertexShader, 1, &vertexShaderSource, 0); 111 | glCompileShader(shader->vertexShader); 112 | glGetShaderiv(shader->vertexShader, GL_INFO_LOG_LENGTH , &logLength); 113 | if (logLength > 1) 114 | { 115 | GLchar* log = (GLchar*)alloca(logLength); 116 | glGetShaderInfoLog(shader->vertexShader, logLength, 0, log); 117 | SDL_Log(log); 118 | assert(0); 119 | return 0; 120 | } 121 | 122 | shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 123 | glShaderSource(shader->fragmentShader, 1, &fragmentShaderSource, 0); 124 | glCompileShader(shader->fragmentShader); 125 | glGetShaderiv(shader->fragmentShader, GL_INFO_LOG_LENGTH , &logLength); 126 | if (logLength > 1) 127 | { 128 | GLchar* log = (GLchar*)alloca(logLength); 129 | glGetShaderInfoLog(shader->fragmentShader, logLength, 0, log); 130 | SDL_Log(log); 131 | assert(0); 132 | return 0; 133 | } 134 | 135 | shader->program = glCreateProgram(); 136 | glAttachShader(shader->program, shader->vertexShader); 137 | glAttachShader(shader->program, shader->fragmentShader); 138 | glLinkProgram(shader->program); 139 | glGetProgramiv(shader->program, GL_INFO_LOG_LENGTH, &logLength); 140 | if (logLength > 1) 141 | { 142 | GLchar* log = (GLchar*)alloca(logLength); 143 | glGetProgramInfoLog(shader->program, logLength, 0, log); 144 | SDL_Log(log); 145 | assert(0); 146 | return 0; 147 | } 148 | 149 | glUseProgram(shader->program); 150 | 151 | shader->matrix = glGetUniformLocation(shader->program, "matrix"); 152 | shader->position = glGetAttribLocation(shader->program, "position"); 153 | 154 | return 1; 155 | } 156 | 157 | void UseCommonShader(const common_shader_t * shader, const float * matrix, const float * vertices) 158 | { 159 | glUseProgram(shader->program); 160 | 161 | glUniformMatrix4fv(shader->matrix, 1, GL_FALSE, matrix); 162 | 163 | glVertexAttribPointer(shader->position, 3, GL_FLOAT, GL_FALSE, 0, vertices); 164 | glEnableVertexAttribArray(shader->position); 165 | } 166 | 167 | 168 | 169 | 170 | struct { 171 | common_shader_t shader; 172 | GLuint color; 173 | } colorShader; 174 | 175 | void CreateColorShader() 176 | { 177 | const GLchar vertexShaderSource[] = { 178 | "#version 150\n" 179 | "uniform mat4 matrix;\n" 180 | "in vec3 position;\n" 181 | "void main()\n" 182 | "{\n" 183 | " gl_Position = matrix * vec4(position, 1.0);\n" 184 | "}" 185 | }; 186 | 187 | const GLchar fragmentShaderSource[] = { 188 | "#version 150\n" 189 | "uniform vec4 color;\n" 190 | "out vec4 outputColor;\n" 191 | "void main()\n" 192 | "{\n" 193 | " outputColor = color;\n" 194 | "}" 195 | }; 196 | 197 | CreateCommonShader(&colorShader.shader, vertexShaderSource, fragmentShaderSource); 198 | 199 | glUseProgram(colorShader.shader.program); 200 | 201 | colorShader.color = glGetUniformLocation(colorShader.shader.program, "color"); 202 | } 203 | 204 | void UseColorShader(float * matrix, float * vertices, int xor, uint8_t color) 205 | { 206 | UseCommonShader(&colorShader.shader, matrix, vertices); 207 | 208 | uint8_t u8[4]; 209 | *(uint32_t*)u8 = GetColor(color); 210 | if (xor) 211 | { 212 | u8[0] = (u8[0] > 127)? 255 : 0; 213 | u8[1] = (u8[1] > 127)? 255 : 0; 214 | u8[2] = (u8[2] > 127)? 255 : 0; 215 | } 216 | glUniform4f(colorShader.color, u8[0]/255.f, u8[1]/255.f, u8[2]/255.f, u8[3]/255.f); 217 | 218 | if (xor) 219 | { 220 | glEnable(GL_BLEND); 221 | glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); 222 | } 223 | else 224 | { 225 | glDisable(GL_BLEND); 226 | } 227 | } 228 | 229 | 230 | 231 | 232 | struct { 233 | common_shader_t shader; 234 | GLuint texcoord; 235 | GLint sampler; 236 | } textureShader; 237 | 238 | void CreateTextureShader() 239 | { 240 | const GLchar vertexShaderSource[] = { 241 | "#version 150\n" 242 | "uniform mat4 matrix;\n" 243 | "in vec3 position;\n" 244 | "in vec2 texcoord;\n" 245 | "out vec2 uv;\n" 246 | "void main()\n" 247 | "{\n" 248 | " gl_Position = matrix * vec4(position, 1.0);\n" 249 | " uv = texcoord;\n" 250 | "}" 251 | }; 252 | 253 | const GLchar fragmentShaderSource[] = { 254 | "#version 150\n" 255 | "uniform sampler2D texUnit;\n" 256 | "in vec2 uv;\n" 257 | "out vec4 outputColor;\n" 258 | "void main()\n" 259 | "{\n" 260 | " outputColor = texture(texUnit, uv);\n" 261 | " if (outputColor.a < 0.1) discard;\n" 262 | "}" 263 | }; 264 | 265 | CreateCommonShader(&textureShader.shader, vertexShaderSource, fragmentShaderSource); 266 | 267 | glUseProgram(textureShader.shader.program); 268 | 269 | textureShader.texcoord = glGetAttribLocation(textureShader.shader.program, "texcoord"); 270 | textureShader.sampler = glGetUniformLocation(textureShader.shader.program, "texUnit"); 271 | } 272 | 273 | void UseTextureShader(float * matrix, float * vertices, int blend, unsigned int texture, float * texcoord) 274 | { 275 | UseCommonShader(&textureShader.shader, matrix, vertices); 276 | 277 | glUniform1i(textureShader.sampler, 0); 278 | glActiveTexture(GL_TEXTURE0); 279 | glBindTexture(GL_TEXTURE_2D, texture); 280 | 281 | if (blend) 282 | { 283 | glEnable(GL_BLEND); 284 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 285 | } 286 | else 287 | { 288 | glDisable(GL_BLEND); 289 | } 290 | 291 | glVertexAttribPointer(textureShader.texcoord, 2, GL_FLOAT, GL_FALSE, 0, texcoord); 292 | glEnableVertexAttribArray(textureShader.texcoord); 293 | } 294 | 295 | 296 | 297 | struct { 298 | common_shader_t shader; 299 | GLuint texcoord; 300 | GLuint color; 301 | GLint sampler; 302 | // GLint sampler2; 303 | } fontShader; 304 | 305 | void CreateFontShader() 306 | { 307 | const GLchar vertexShaderSource[] = { 308 | "#version 150\n" 309 | "uniform mat4 matrix;\n" 310 | "in vec3 position;\n" 311 | "in vec2 texcoord;\n" 312 | "out vec2 uv;\n" 313 | // "out vec2 uv2;\n" // test 314 | "void main()\n" 315 | "{\n" 316 | " gl_Position = matrix * vec4(position, 1.0);\n" 317 | " uv = texcoord;\n" 318 | // " uv2 = position.xy * vec2(0.5,-0.5) + vec2(0.5,0.5);\n" // test 319 | "}" 320 | }; 321 | 322 | const GLchar fragmentShaderSource[] = { 323 | "#version 150\n" 324 | "uniform vec4 color;\n" 325 | "uniform sampler2D texUnit;\n" 326 | // "uniform sampler2D texUnit2;\n" // test 327 | "in vec2 uv;\n" 328 | // "in vec2 uv2;\n" // test 329 | "out vec4 outputColor;\n" 330 | "void main()\n" 331 | "{\n" 332 | " vec4 texel = texture(texUnit, uv);\n" 333 | " if (texel.a < 0.5) discard;\n" 334 | // " texel = vec4(1,1,1,1) - texture(texUnit2, uv2);\n" // test 335 | " outputColor = vec4(texel.rgb * color.rgb, 1);\n" 336 | "}" 337 | }; 338 | 339 | CreateCommonShader(&fontShader.shader, vertexShaderSource, fragmentShaderSource); 340 | 341 | glUseProgram(fontShader.shader.program); 342 | 343 | fontShader.texcoord = glGetAttribLocation(fontShader.shader.program, "texcoord"); 344 | fontShader.color = glGetUniformLocation(fontShader.shader.program, "color"); 345 | fontShader.sampler = glGetUniformLocation(fontShader.shader.program, "texUnit"); 346 | // fontShader.sampler2 = glGetUniformLocation(fontShader.shader.program, "texUnit2"); 347 | } 348 | 349 | void UseFontShader(float * matrix, float * vertices, int blend, uint8_t color, GLuint texture, float * texcoord) 350 | { 351 | UseCommonShader(&fontShader.shader, matrix, vertices); 352 | 353 | uint8_t u8[4]; 354 | *(uint32_t*)u8 = GetColor(color); 355 | glUniform4f(fontShader.color, u8[0]/255.f, u8[1]/255.f, u8[2]/255.f, u8[3]/255.f); 356 | 357 | glUniform1i(fontShader.sampler, 0); 358 | glActiveTexture(GL_TEXTURE0); 359 | glBindTexture(GL_TEXTURE_2D, texture); 360 | 361 | // glUniform1i(fontShader.sampler2, 1); 362 | // glActiveTexture(GL_TEXTURE1); 363 | // glBindTexture(GL_TEXTURE_2D, fbo.texture[video_screenofs_fbo]); 364 | 365 | if (blend) 366 | { 367 | glEnable(GL_BLEND); 368 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 369 | } 370 | else 371 | { 372 | glDisable(GL_BLEND); 373 | } 374 | 375 | glVertexAttribPointer(fontShader.texcoord, 2, GL_FLOAT, GL_FALSE, 0, texcoord); 376 | glEnableVertexAttribArray(fontShader.texcoord); 377 | } 378 | 379 | 380 | 381 | GLuint fadeVertexShader; 382 | GLuint fadeFragmentShader; 383 | GLuint fadeProgram; 384 | GLuint fadeTexcoordLocation; 385 | GLuint fadePositionLocation; 386 | GLuint fadeFadeLocation; 387 | GLint fadeSamplerLocation; 388 | 389 | void CreateFadeShader() 390 | { 391 | GLint logLength; 392 | 393 | const GLchar *vertexShaderSource[] = { 394 | "#version 150\n" 395 | "in vec2 texcoord;\n" 396 | "in vec2 position;\n" 397 | "out vec2 uv;\n" 398 | "void main()\n" 399 | "{\n" 400 | " gl_Position = vec4(position, 0.0, 1.0);\n" 401 | " uv = texcoord;\n" 402 | "}" 403 | }; 404 | 405 | const GLchar *fragmentShaderSource[] = { 406 | "#version 150\n" 407 | "uniform float fade;\n" 408 | "uniform sampler2D texUnit;\n" 409 | "in vec2 uv;\n" 410 | "out vec4 outputColor;\n" 411 | "void main()\n" 412 | "{\n" 413 | " vec4 color = texture(texUnit, uv);\n" 414 | " vec4 darken = color * min(fade,1.0);\n" 415 | " vec4 brighten = (darken - vec4(1.0,1.0,1.0,1.0)) * (2 - max(fade,1.0)) + vec4(1.0,1.0,1.0,1.0);\n" 416 | " outputColor = brighten;\n" 417 | "}" 418 | }; 419 | 420 | fadeVertexShader = glCreateShader(GL_VERTEX_SHADER); 421 | glShaderSource(fadeVertexShader, 1, vertexShaderSource, 0); 422 | glCompileShader(fadeVertexShader); 423 | glGetShaderiv(fadeVertexShader, GL_INFO_LOG_LENGTH , &logLength); 424 | if (logLength > 1) 425 | { 426 | GLchar* log = (GLchar*)alloca(logLength); 427 | glGetShaderInfoLog(fadeVertexShader, logLength, 0, log); 428 | SDL_Log(log); 429 | assert(0); 430 | } 431 | 432 | fadeFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 433 | glShaderSource(fadeFragmentShader, 1, fragmentShaderSource, 0); 434 | glCompileShader(fadeFragmentShader); 435 | glGetShaderiv(fadeFragmentShader, GL_INFO_LOG_LENGTH , &logLength); 436 | if (logLength > 1) 437 | { 438 | GLchar* log = (GLchar*)alloca(logLength); 439 | glGetShaderInfoLog(fadeFragmentShader, logLength, 0, log); 440 | SDL_Log(log); 441 | assert(0); 442 | } 443 | 444 | fadeProgram = glCreateProgram(); 445 | glAttachShader(fadeProgram, fadeVertexShader); 446 | glAttachShader(fadeProgram, fadeFragmentShader); 447 | glLinkProgram(fadeProgram); 448 | glUseProgram(fadeProgram); 449 | 450 | fadeTexcoordLocation = glGetAttribLocation(fadeProgram, "texcoord"); 451 | fadePositionLocation = glGetAttribLocation(fadeProgram, "position"); 452 | fadeSamplerLocation = glGetUniformLocation(fadeProgram, "texUnit"); 453 | fadeFadeLocation = glGetUniformLocation(fadeProgram, "fade"); 454 | } 455 | 456 | void UseFadeShader(float fade, GLuint texture, float * vertices, float * texcoords) 457 | { 458 | glUseProgram(fadeProgram); 459 | 460 | glUniform1i(fadeSamplerLocation, 0); 461 | glUniform1f(fadeFadeLocation, fade); 462 | glActiveTexture(GL_TEXTURE0); 463 | glBindTexture(GL_TEXTURE_2D, texture); 464 | 465 | glDisable(GL_BLEND); 466 | 467 | glVertexAttribPointer(fadeTexcoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords); 468 | glEnableVertexAttribArray(fadeTexcoordLocation); 469 | glVertexAttribPointer(fadePositionLocation, 2, GL_FLOAT, GL_FALSE, 0, vertices); 470 | glEnableVertexAttribArray(fadePositionLocation); 471 | } 472 | 473 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /IDLIBC.C: -------------------------------------------------------------------------------- 1 | 2 | #include "IDLIB.H" 3 | #include "IDLIB_SDL.H" 4 | 5 | #include 6 | 7 | #define BLANKCHAR 9 8 | 9 | int JoyXlow [3], JoyXhigh [3], JoyYlow [3], JoyYhigh [3], buttonflip; 10 | 11 | #if NUMPICS>0 12 | pictype pictable[NUMPICS]; 13 | #endif 14 | 15 | memptr grsegs[NUMCHUNKS]; 16 | char needgr[NUMCHUNKS]; // for caching 17 | 18 | inputtype playermode[3]; 19 | 20 | /* 21 | =============== 22 | = 23 | = OptimizeNodes 24 | = 25 | = Goes through a huffman table and changes the 256-511 node numbers to the 26 | = actular address of the node. Must be called before HuffExpand 27 | = 28 | =============== 29 | */ 30 | 31 | void OptimizeNodes (huffnode *table) 32 | { 33 | // only works on older systems 34 | } 35 | 36 | 37 | 38 | /* 39 | ====================== 40 | = 41 | = HuffExpand 42 | = 43 | ====================== 44 | */ 45 | 46 | void HuffExpand (unsigned char *source, unsigned char *dest, 47 | int32_t length,huffnode *hufftable) 48 | { 49 | unsigned bit,byte,code; 50 | huffnode *nodeon,*headptr; 51 | 52 | headptr = hufftable+254; // head node is allways node 254 53 | nodeon = headptr; 54 | 55 | bit = 1; 56 | byte = *source++; 57 | 58 | while (length) 59 | { 60 | if (byte&bit) 61 | code = nodeon->bit1; 62 | else 63 | code = nodeon->bit0; 64 | 65 | bit<<=1; 66 | if (bit==256) 67 | { 68 | bit=1; 69 | byte = *source++; 70 | } 71 | 72 | if (code<256) 73 | { 74 | *dest++=code; 75 | nodeon=headptr; 76 | length--; 77 | } 78 | else 79 | { 80 | nodeon = &hufftable[code-256]; 81 | } 82 | } 83 | 84 | #if 0 85 | huffnode *headptr; 86 | headptr = Hufftable+254; // head node is allways node 254 87 | 88 | huffnode *curhuffnode = headptr; 89 | int i, j; 90 | int written = 0; 91 | i = 0; 92 | while (written < length) { 93 | uint8_t srcbyte = Source[i++]; 94 | for (j = 0; j < 8; j++) { 95 | unsigned short b = curhuffnode->bit0; 96 | if (srcbyte&1) { 97 | b = curhuffnode->bit1; 98 | } 99 | srcbyte = srcbyte>>1; 100 | if (b < 256) { 101 | Dest[written++] = (uint8_t)b; 102 | curhuffnode = headptr; 103 | if (written == length) { 104 | break; 105 | } 106 | } else { 107 | assert(b-256 >= 0); 108 | curhuffnode = &Hufftable[b-256]; 109 | } 110 | } 111 | } 112 | #endif 113 | } 114 | 115 | /*========================================================================*/ 116 | 117 | 118 | /* 119 | ====================== 120 | = 121 | = RLEWexpand 122 | = 123 | ====================== 124 | */ 125 | #define RLETAG 0xFEFE 126 | 127 | void RLEWExpand (unsigned short *source, unsigned short *dest) 128 | { 129 | int32_t length; 130 | uint16_t value,count,i; 131 | uint16_t *start, *end; 132 | 133 | length = *(int32_t*)source; 134 | end = dest + (length)/2; 135 | 136 | source+=2; // skip length words 137 | // 138 | // expand it 139 | // 140 | do 141 | { 142 | value = *source++; 143 | if (value != RLETAG) 144 | // 145 | // uncompressed 146 | // 147 | *dest++=value; 148 | else 149 | { 150 | // 151 | // compressed string 152 | // 153 | count = *source++; 154 | value = *source++; 155 | if (dest+count>end) 156 | Quit("RLEWExpand error!"); 157 | 158 | for (i=1;i<=count;i++) 159 | *dest++ = value; 160 | } 161 | } while (dest=0x3b && sc<=0x44) 386 | { 387 | char str[3]; 388 | PPrint ("F"); 389 | itoa (sc-0x3a,str,10); 390 | PPrint (str); 391 | } 392 | else if (sc==0x57) 393 | PPrint ("F11"); 394 | else if (sc==0x59) 395 | PPrint ("F12"); 396 | else if (sc==0x46) 397 | PPrint ("SCRLLK"); 398 | else if (sc==0x1c) 399 | PPrint ("ENTER"); 400 | else if (sc==0x36) 401 | PPrint ("RSHIFT"); 402 | else if (sc==0x37) 403 | PPrint ("PRTSC"); 404 | else if (sc==0x38) 405 | PPrint ("ALT"); 406 | else if (sc==0x47) 407 | PPrint ("HOME"); 408 | else if (sc==0x49) 409 | PPrint ("PGUP"); 410 | else if (sc==0x4f) 411 | PPrint ("END"); 412 | else if (sc==0x51) 413 | PPrint ("PGDN"); 414 | else if (sc==0x52) 415 | PPrint ("INS"); 416 | else if (sc==0x53) 417 | PPrint ("DEL"); 418 | else if (sc==0x45) 419 | PPrint ("NUMLK"); 420 | else if (sc==0x48) 421 | PPrint ("UP"); 422 | else if (sc==0x50) 423 | PPrint ("DOWN"); 424 | else if (sc==0x4b) 425 | PPrint ("LEFT"); 426 | else if (sc==0x4d) 427 | PPrint ("RIGHT"); 428 | else 429 | { 430 | str[0]=chartable[sc]; 431 | str[1]=0; 432 | PPrint (str); 433 | } 434 | } 435 | 436 | ///////////////////////////// 437 | // 438 | // calibratekeys 439 | // 440 | //////////////////////////// 441 | void calibratekeys (void) 442 | { 443 | char ch; 444 | int hx,hy,i,select,_new; 445 | 446 | ExpWin (22,12); 447 | fontcolor=13; 448 | CPPrint ("Keyboard Configuration"); 449 | fontcolor=15; 450 | PPrint ("\n1 north"); 451 | PPrint ("\n2 east"); 452 | PPrint ("\n3 south"); 453 | PPrint ("\n4 west"); 454 | PPrint ("\n5 button1"); 455 | PPrint ("\n6 button2"); 456 | PPrint ("\nModify which action:"); 457 | hx=(px+7)/8; 458 | hy=py; 459 | for (i=0;i<4;i++) 460 | { 461 | px=pxl+8*12; 462 | py=pyl+10*(1+i); 463 | PPrint(":"); 464 | printscan (key[i*2]); 465 | } 466 | px=pxl+8*12; 467 | py=pyl+10*5; 468 | PPrint(":"); 469 | printscan (keyB1); 470 | px=pxl+8*12; 471 | py=pyl+10*6; 472 | PPrint(":"); 473 | printscan (keyB2); 474 | 475 | do 476 | { 477 | px=hx*8; 478 | py=hy; 479 | DrawChar (hx,hy,BLANKCHAR); 480 | ch=PGet() % 256; 481 | if (ch<'1' || ch>'6') 482 | continue; 483 | select = ch - '1'; 484 | DrawPchar (ch); 485 | PPrint ("\nPress the new key:"); 486 | ClearKeys (); 487 | _new=-1; 488 | while (!keydown[++_new]) 489 | if (_new==0x79) 490 | _new=-1; 491 | else if (_new==0x29) 492 | _new++; // skip STUPID left shifts! 493 | Bar(leftedge,py,22,10,0xff); 494 | if (select<4) 495 | key[select*2]=_new; 496 | if (select==4) 497 | keyB1=_new; 498 | if (select==5) 499 | keyB2=_new; 500 | px=pxl+8*12; 501 | py=pyl+(select+1)*10; 502 | Bar(px/8,py,9,10,0xff); 503 | PPrint (":"); 504 | printscan (_new); 505 | ClearKeys (); 506 | ch='0'; // so the loop continues 507 | } while (ch>='0' && ch<='9'); 508 | playermode[1]=keyboard; 509 | } 510 | 511 | 512 | /* 513 | ============================================================================ 514 | 515 | MID LEVEL GRAPHIC ROUTINES 516 | 517 | ============================================================================ 518 | */ 519 | 520 | #define DRAWCHAR(x,y,n) DrawChar(x,(y)*8,n) 521 | 522 | int win_xl,win_yl,win_xh,win_yh; 523 | 524 | int sx,sy,leftedge; 525 | 526 | int screencenterx = 20,screencentery = 11; 527 | 528 | 529 | ////////////////////////// 530 | // 531 | // DrawWindow 532 | // draws a bordered window and homes the cursor 533 | // 534 | ////////////////////////// 535 | 536 | void DrawWindow (int xl, int yl, int xh, int yh) 537 | { 538 | int x,y; 539 | win_xl=xl; 540 | pxl = xl*8+8; 541 | win_yl=yl; 542 | win_xh=xh; 543 | pxh = xh*8; 544 | win_yh=yh; // so the window can be erased 545 | 546 | DRAWCHAR (xl,yl,1); 547 | for (x=xl+1;x 2) 606 | { 607 | if (height >2) 608 | ExpWin (width-2,height-2); 609 | else 610 | ExpWinH (width-2,height); 611 | } 612 | else 613 | if (height >2) 614 | ExpWinV (width,height-2); 615 | 616 | WaitVBL (1); 617 | CenterWindow (width,height); 618 | } 619 | 620 | void ExpWinH (int width, int height) 621 | { 622 | if (width > 2) 623 | ExpWinH (width-2,height); 624 | 625 | WaitVBL (1); 626 | CenterWindow (width,height); 627 | } 628 | 629 | void ExpWinV (int width, int height) 630 | { 631 | if (height >2) 632 | ExpWinV (width,height-2); 633 | 634 | WaitVBL (1); 635 | CenterWindow (width,height); 636 | } 637 | 638 | /* 639 | =========================================================================== 640 | 641 | CHARACTER BASED PRINTING ROUTINES 642 | 643 | =========================================================================== 644 | */ 645 | 646 | ///////////////////////// 647 | // 648 | // Print 649 | // Prints a string at sx,sy. No clipping!!! 650 | // 651 | ///////////////////////// 652 | 653 | void Print (const char *str) 654 | { 655 | unsigned char ch; 656 | 657 | while ((ch=*str++) != 0) 658 | if (ch == '\n') 659 | { 660 | sy++; 661 | sx=leftedge; 662 | } 663 | else if (ch == '\r') 664 | sx=leftedge; 665 | else 666 | DRAWCHAR (sx++,sy,ch); 667 | } 668 | 669 | 670 | 671 | 672 | 673 | 674 | //////////////////////////////////////////////////////////////////// 675 | // 676 | // Input unsigned 677 | // 678 | //////////////////////////////////////////////////////////////////// 679 | unsigned InputInt(void) 680 | { 681 | char string[18]="",digit,hexstr[17]="0123456789ABCDEF"; 682 | unsigned value,loop,loop1; 683 | 684 | Input(string,2); 685 | if (string[0]=='$') 686 | { 687 | int digits; 688 | 689 | digits=strlen(string)-2; 690 | if (digits<0) return 0; 691 | 692 | for (value=0,loop1=0;loop1<=digits;loop1++) 693 | { 694 | digit=toupper(string[loop1+1]); 695 | for (loop=0;loop<16;loop++) 696 | if (digit==hexstr[loop]) 697 | { 698 | value|=(loop<<(digits-loop1)*4); 699 | break; 700 | } 701 | } 702 | } 703 | else if (string[0]=='%') 704 | { 705 | int digits; 706 | 707 | digits=strlen(string)-2; 708 | if (digits<0) return 0; 709 | 710 | for (value=0,loop1=0;loop1<=digits;loop1++) 711 | { 712 | if (string[loop1+1]<'0' || string[loop1+1]>'1') return 0; 713 | value|=(string[loop1+1]-'0')<<(digits-loop1); 714 | } 715 | } 716 | else value=atoi(string); 717 | return value; 718 | } 719 | 720 | 721 | 722 | 723 | //////////////////////////////////////////////////////////////////// 724 | // 725 | // line Input routine (PROPORTIONAL) 726 | // 727 | //////////////////////////////////////////////////////////////////// 728 | int Input(char *string,int max) 729 | { 730 | char key; 731 | int count=0,loop; 732 | int pxt[90]; 733 | pxt[0]=px; 734 | 735 | do { 736 | key=toupper(PGet()&0xff); 737 | if ((key==127 || key==8)&&count>0) 738 | { 739 | count--; 740 | px=pxt[count]; 741 | DrawPchar(string[count]); 742 | px=pxt[count]; 743 | } 744 | 745 | if (key>=' ' && key<='z' && countwidth[ch]; 840 | } 841 | 842 | return length; 843 | } 844 | 845 | 846 | ///////////////////////// 847 | // 848 | // CPPrint 849 | // Centers the string between pxl/pxh 850 | // 851 | ///////////////////////// 852 | 853 | void CPPrint (const char *str) 854 | { 855 | int width; 856 | 857 | width = PSize(str); 858 | px=pxl+(int)(pxh-pxl-width)/2; 859 | PPrint (str); 860 | } 861 | 862 | 863 | void PPrintUnsigned (unsigned val) 864 | { 865 | char str[512]; 866 | ltoa((int32_t)val,str,10); 867 | PPrint (str); 868 | } 869 | 870 | void PPrintInt (int val) 871 | { 872 | char str[512]; 873 | itoa(val,str,10); 874 | PPrint (str); 875 | } 876 | 877 | -------------------------------------------------------------------------------- /HOVTRACE.C: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "HOVERDEF.H" 20 | 21 | //========================================================================== 22 | 23 | int FinishWall (void); 24 | 25 | //========================================================================== 26 | 27 | fixed edgex,edgey; 28 | 29 | int wallon; 30 | int basecolor; 31 | 32 | walltype *oldwall; 33 | 34 | // 35 | // offsets from upper left corner of a tile to the left and right edges of 36 | // a given wall (NORTH-WEST) 37 | // 38 | fixed point1x[4] = {GLOBAL1,GLOBAL1,0 ,0 }; 39 | fixed point1y[4] = {0 ,GLOBAL1,GLOBAL1,0 }; 40 | 41 | fixed point2x[4] = {0 ,GLOBAL1,GLOBAL1,0 }; 42 | fixed point2y[4] = {0 ,0 ,GLOBAL1 ,GLOBAL1}; 43 | 44 | 45 | // 46 | // offset from tile.x,tile.y of the tile that shares wallon side 47 | // (side is not visable if it is shared) 48 | // 49 | int sharex[4] = { 0, 1, 0,-1}; 50 | int sharey[4] = {-1, 0, 1, 0}; 51 | 52 | // 53 | // amount to move tile.x,tile.y to follow wallon to another tile 54 | // 55 | int followx[4] = {-1, 0, 1, 0}; 56 | int followy[4] = { 0,-1, 0, 1}; 57 | 58 | // 59 | // cornerwall gives the wall on the same tile to start following when the 60 | // wall ends at an empty tile (go around an edge on same tile) 61 | // turnwall gives the wall on tile.x+sharex,tile.y+sharey to start following 62 | // when the wall hits another tile (right angle corner) 63 | // 64 | int cornerwall[4] = {WEST,NORTH,EAST,SOUTH}; 65 | int turnwall[4] = {EAST,SOUTH,WEST,NORTH}; 66 | 67 | // 68 | // wall visabilities in reletive locations 69 | // -,- 0,- +,- 70 | // -,0 0,0 +,0 71 | // -,+ 0,+ +,+ 72 | // 73 | int visable[9][4] = 74 | { 75 | {0,1,1,0}, {0,0,1,0}, {0,0,1,1}, 76 | {0,1,0,0}, {0,0,0,0}, {0,0,0,1}, 77 | {1,1,0,0}, {1,0,0,0}, {1,0,0,1} 78 | }; 79 | 80 | int startwall[9] = {2,2,3, 1,0,3, 1,0,0}; 81 | int backupwall[9] = {3,3,0, 2,0,0, 2,1,1}; 82 | 83 | 84 | 85 | /* 86 | ======================== 87 | = 88 | = FollowTrace 89 | = 90 | ======================== 91 | */ 92 | 93 | int FollowTrace (fixed tracex, fixed tracey, int32_t deltax, int32_t deltay, int max) 94 | { 95 | int tx,ty,otx,oty; 96 | int32_t absdx,absdy,xstep,ystep; 97 | 98 | tx = tracex>>TILESHIFT; 99 | ty = tracey>>TILESHIFT; 100 | 101 | absdx=LABS(deltax); 102 | absdy=LABS(deltay); 103 | 104 | if (absdx>absdy) 105 | { 106 | ystep = (deltay<<8)/(absdx>>8); 107 | 108 | if (!ystep) 109 | ystep = deltay>0 ? 1 : -1; 110 | 111 | oty = (tracey+ystep)>>TILESHIFT; 112 | if (deltax>0) 113 | { 114 | //############### 115 | // 116 | // step x by +1 117 | // 118 | //############### 119 | do 120 | { 121 | tx++; 122 | tracey+=ystep; 123 | ty = tracey>>TILESHIFT; 124 | 125 | if (ty!=oty) 126 | { 127 | if (tilemap[tx-1][ty]) 128 | { 129 | tile.x = tx-1; 130 | tile.y = ty; 131 | return 1; 132 | } 133 | oty = ty; 134 | } 135 | if (tilemap[tx][ty]) 136 | { 137 | tile.x = tx; 138 | tile.y = ty; 139 | return 1; 140 | } 141 | } while (--max); 142 | return 0; 143 | } 144 | else 145 | { 146 | //############### 147 | // 148 | // step x by -1 149 | // 150 | //############### 151 | do 152 | { 153 | tx--; 154 | tracey+=ystep; 155 | ty = tracey>>TILESHIFT; 156 | 157 | if (ty!=oty) 158 | { 159 | if (tilemap[tx][oty]) 160 | { 161 | tile.x = tx; 162 | tile.y = oty; 163 | return 1; 164 | } 165 | oty = ty; 166 | } 167 | if (tilemap[tx][ty]) 168 | { 169 | tile.x = tx; 170 | tile.y = ty; 171 | return 1; 172 | } 173 | } while (--max); 174 | return 0; 175 | 176 | } 177 | } 178 | else 179 | { 180 | xstep = (deltax<<8)/(absdy>>8); 181 | if (!xstep) 182 | xstep = deltax>0 ? 1 : -1; 183 | 184 | 185 | otx = (tracex+xstep)>>TILESHIFT; 186 | if (deltay>0) 187 | { 188 | //############### 189 | // 190 | // step y by +1 191 | // 192 | //############### 193 | do 194 | { 195 | ty++; 196 | tracex+=xstep; 197 | tx = tracex>>TILESHIFT; 198 | 199 | if (tx!=otx) 200 | { 201 | if (tilemap[tx][ty-1]) 202 | { 203 | tile.x = tx; 204 | tile.y = ty-1; 205 | return 1; 206 | } 207 | otx = tx; 208 | } 209 | if (tilemap[tx][ty]) 210 | { 211 | tile.x = tx; 212 | tile.y = ty; 213 | return 1; 214 | } 215 | } while (--max); 216 | return 0; 217 | } 218 | else 219 | { 220 | //############### 221 | // 222 | // step y by -1 223 | // 224 | //############### 225 | do 226 | { 227 | ty--; 228 | tracex+=xstep; 229 | tx = tracex>>TILESHIFT; 230 | 231 | if (tx!=otx) 232 | { 233 | if (tilemap[otx][ty]) 234 | { 235 | tile.x = otx; 236 | tile.y = ty; 237 | return 1; 238 | } 239 | otx = tx; 240 | } 241 | if (tilemap[tx][ty]) 242 | { 243 | tile.x = tx; 244 | tile.y = ty; 245 | return 1; 246 | } 247 | } while (--max); 248 | return 0; 249 | } 250 | 251 | } 252 | 253 | } 254 | 255 | 256 | //=========================================================================== 257 | 258 | 259 | /* 260 | ================= 261 | = 262 | = BackTrace 263 | = 264 | = Traces backwards from edgex,edgey to viewx,viewy to see if a closer 265 | = tile obscures the given point. If it does, it finishes the wall and 266 | = starts a new one. 267 | = Returns true if a tile is hit. 268 | = Call with a 1 to have it automatically finish the current wall 269 | = 270 | ================= 271 | */ 272 | 273 | int BackTrace (int finish) 274 | { 275 | fixed tracex,tracey; 276 | int32_t deltax,deltay,absdx,absdy; 277 | int steps,otx,oty,testx,testheight,offset,wall; 278 | 279 | deltax = viewx-edgex; 280 | deltay = viewy-edgey; 281 | 282 | absdx = LABS(deltax); 283 | absdy = LABS(deltay); 284 | 285 | if (absdx>absdy) 286 | steps = ABS(focal.x-(edgex>>TILESHIFT))-1; 287 | else 288 | steps = ABS(focal.y-(edgey>>TILESHIFT))-1; 289 | 290 | if (steps<=0) 291 | return 0; 292 | 293 | otx = tile.x; 294 | oty = tile.y; 295 | if (!FollowTrace(edgex,edgey,deltax,deltay,steps)) 296 | return 0; 297 | 298 | // 299 | // if the start wall is behind the focal point, the trace went too far back 300 | // 301 | if (ABS(tile.x-focal.x)<2 && ABS(tile.y-focal.y)<2) // too close 302 | { 303 | if (tile.x == focal.x && tile.y == focal.y) 304 | { 305 | tile.x = otx; 306 | tile.y = oty; 307 | return 0; 308 | } 309 | 310 | if (tile.xx1 = oldwall->x2; // common edge with last wall 353 | rightwall->height1 = oldwall->height2; 354 | rightwall->wx0 = oldwall->wx1; 355 | rightwall->wz0 = oldwall->wz1; 356 | return 0; 357 | } 358 | 359 | 360 | // 361 | // back up along the intersecting face to find the rightmost wall 362 | // 363 | 364 | if (tile.yfocal.x) 373 | offset += 2; 374 | 375 | wallon = backupwall[offset]; 376 | 377 | while (tilemap[tile.x][tile.y]) 378 | { 379 | tile.x += followx[wallon]; 380 | tile.y += followy[wallon]; 381 | }; 382 | 383 | tile.x -= followx[wallon]; 384 | tile.y -= followy[wallon]; 385 | 386 | wallon = cornerwall[wallon]; // turn to first visable face 387 | 388 | edgex = ((int32_t)tile.x<<16); 389 | edgey = ((int32_t)tile.y<<16); 390 | 391 | rightwall->wx0 = edgex+point1x[wallon]; 392 | rightwall->wz0 = edgey+point1y[wallon]; 393 | TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon], 394 | &rightwall->x1,&rightwall->height1); 395 | 396 | basecolor = tilemap[tile.x][tile.y]; 397 | 398 | return 1; 399 | } 400 | 401 | //=========================================================================== 402 | 403 | 404 | /* 405 | ================= 406 | = 407 | = ForwardTrace 408 | = 409 | = Traces forwards from edgex,edgey along the line from viewx,viewy until 410 | = a solid tile is hit. Sets tile.x,tile.y 411 | = 412 | ================= 413 | */ 414 | 415 | void ForwardTrace (void) 416 | { 417 | int offset; 418 | fixed tracex,tracey; 419 | int32_t deltax,deltay; 420 | 421 | deltax = edgex-viewx; 422 | deltay = edgey-viewy; 423 | 424 | FollowTrace(edgex,edgey,deltax,deltay,0); 425 | 426 | if (tile.yfocal.x) 435 | offset += 2; 436 | 437 | wallon = startwall[offset]; 438 | 439 | // 440 | // start the new wall 441 | // 442 | edgex = ((int32_t)tile.x<<16); 443 | edgey = ((int32_t)tile.y<<16); 444 | 445 | // 446 | // if entire first wall is invisable, corner 447 | // 448 | rightwall->wx1 = edgex+point2x[wallon]; 449 | rightwall->wz1 = edgey+point2y[wallon]; 450 | TransformPoint (edgex+point2x[wallon],edgey+point2y[wallon], 451 | &rightwall->x2,&rightwall->height2); 452 | 453 | if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]] 454 | || rightwall->x2 < (rightwall-1)->x2 ) 455 | wallon = cornerwall [wallon]; 456 | 457 | // 458 | // transform first point 459 | // 460 | 461 | rightwall->wx0 = edgex+point1x[wallon]; 462 | rightwall->wz0 = edgey+point1y[wallon]; 463 | TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon], 464 | &rightwall->x1,&rightwall->height1); 465 | 466 | basecolor = tilemap[tile.x][tile.y]; 467 | } 468 | 469 | 470 | //=========================================================================== 471 | 472 | 473 | /* 474 | ================= 475 | = 476 | = FinishWall 477 | = 478 | = Transforms edgex,edgey as the next point of the current wall 479 | = and sticks it in the wall list 480 | = 481 | ================= 482 | */ 483 | 484 | int FinishWall (void) 485 | { 486 | char num[20]; 487 | 488 | oldwall = rightwall; 489 | 490 | if (wallon&1) 491 | rightwall->color = basecolor+8; // high intensity walls 492 | else 493 | rightwall->color = basecolor; 494 | 495 | rightwall->wx1 = edgex; 496 | rightwall->wz1 = edgey; 497 | TransformPoint (edgex,edgey,&rightwall->x2,&rightwall->height2); 498 | 499 | if (rightwall->x2 <= (rightwall-1)->x2+2 500 | && rightwall->height2 < (rightwall-1)->height2 ) 501 | return 0; 502 | 503 | rightwall++; 504 | 505 | return 1; 506 | } 507 | 508 | //=========================================================================== 509 | 510 | 511 | /* 512 | ================= 513 | = 514 | = InsideCorner 515 | = 516 | ================= 517 | */ 518 | 519 | void InsideCorner (void) 520 | { 521 | int offset; 522 | 523 | // 524 | // the wall turned -90 degrees, so draw what we have, move to the new tile, 525 | // change wallon, change color, and continue following. 526 | // 527 | FinishWall (); 528 | 529 | tile.x += sharex[wallon]; 530 | tile.y += sharey[wallon]; 531 | 532 | wallon = turnwall[wallon]; 533 | 534 | // 535 | // if the new wall is visable, continue following it. Otherwise 536 | // follow it backwards until it turns 537 | // 538 | if (tile.yfocal.x) 547 | offset += 2; 548 | 549 | if (visable[offset][wallon]) 550 | { 551 | // 552 | // just turn to the next wall and continue 553 | // 554 | rightwall->x1 = oldwall->x2; // common edge with last wall 555 | rightwall->height1 = oldwall->height2; 556 | rightwall->wx0 = oldwall->wx1; 557 | rightwall->wz0 = oldwall->wz1; 558 | basecolor = tilemap[tile.x][tile.y]; 559 | return; // continue from here 560 | } 561 | 562 | // 563 | // back follow the invisable wall until it turns, then follow that 564 | // 565 | do 566 | { 567 | tile.x += followx[wallon]; 568 | tile.y += followy[wallon]; 569 | } while (tilemap[tile.x][tile.y]); 570 | 571 | tile.x -= followx[wallon]; 572 | tile.y -= followy[wallon]; 573 | 574 | wallon = cornerwall[wallon]; // turn to first visable face 575 | 576 | edgex = ((int32_t)tile.x<<16)+point1x[wallon]; 577 | edgey = ((int32_t)tile.y<<16)+point1y[wallon]; 578 | 579 | if (!BackTrace(0)) // backtrace without finishing a wall 580 | { 581 | rightwall->wx0 = edgex; 582 | rightwall->wz0 = edgey; 583 | TransformPoint (edgex,edgey,&rightwall->x1,&rightwall->height1); 584 | basecolor = tilemap[tile.x][tile.y]; 585 | } 586 | } 587 | 588 | //=========================================================================== 589 | 590 | 591 | /* 592 | ================= 593 | = 594 | = OutsideCorner 595 | = 596 | ================= 597 | */ 598 | 599 | void OutsideCorner (void) 600 | { 601 | int offset; 602 | 603 | // 604 | // edge is the outside edge of a corner, so draw the current wall and 605 | // turn the corner (+90 degrees) 606 | // 607 | FinishWall (); 608 | 609 | tile.x -= followx[wallon]; // backup to the real tile 610 | tile.y -= followy[wallon]; 611 | wallon = cornerwall[wallon]; 612 | 613 | // 614 | // if the new wall is visable, continue following it. Otherwise 615 | // trace a ray from the corner to find a wall in the distance to 616 | // follow 617 | // 618 | if (tile.yfocal.x) 627 | offset += 2; 628 | 629 | if (visable[offset][wallon]) 630 | { 631 | // 632 | // the new wall is visable, so just continue on 633 | // 634 | rightwall->x1 = oldwall->x2; // common edge with last wall 635 | rightwall->height1 = oldwall->height2; 636 | rightwall->wx0 = oldwall->wx1; 637 | rightwall->wz0 = oldwall->wz1; 638 | return; // still on same tile, so color is ok 639 | } 640 | 641 | // 642 | // start from a new tile further away 643 | // 644 | ForwardTrace(); // find the next wall further back 645 | 646 | } 647 | 648 | 649 | //=========================================================================== 650 | 651 | 652 | /* 653 | ================= 654 | = 655 | = FollowWalls 656 | = 657 | = Starts a wall edge at the leftmost edge of tile.x,tile.y and follows it 658 | = until something else is seen or the entire view area is covered 659 | = 660 | ================= 661 | */ 662 | 663 | void FollowWalls (void) 664 | { 665 | int height,newcolor,offset,wall; 666 | 667 | //#################### 668 | // 669 | // figure leftmost wall of new tile 670 | // 671 | //#################### 672 | 673 | restart: 674 | 675 | if (tile.yfocal.x) 684 | offset += 2; 685 | 686 | wallon = startwall[offset]; 687 | 688 | // 689 | // if the start wall is inside a block, skip it by cornering to the second wall 690 | // 691 | if ( tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]]) 692 | wallon = cornerwall [wallon]; 693 | 694 | // 695 | // transform first edge to screen coordinates 696 | // 697 | edgex = ((int32_t)tile.x<<16); 698 | edgey = ((int32_t)tile.y<<16); 699 | 700 | rightwall->wx0 = edgex+point1x[wallon]; 701 | rightwall->wz0 = edgey+point1y[wallon]; 702 | TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon], 703 | &rightwall->x1,&rightwall->height1); 704 | 705 | basecolor = tilemap[tile.x][tile.y]; 706 | 707 | //################## 708 | // 709 | // follow the wall as long as possible 710 | // 711 | //################## 712 | 713 | advance: 714 | 715 | do // while ( tile.x != right.x || tile.y != right.y) 716 | { 717 | // 718 | // check for conditions that shouldn't happed... 719 | // 720 | if (rightwall->x1 > VIEWXH) // somehow missed right tile... 721 | return; 722 | 723 | if (rightwall == &walls[DANGERHIGH]) 724 | { 725 | // 726 | // somethiing got messed up! Correct by thrusting ahead... 727 | // 728 | ColorBorder(15); 729 | bordertime = 60; 730 | Thrust(); 731 | if (++obon.angle==ANGLES) 732 | obon.angle = 0; 733 | objlist[0] = obon; 734 | StartView (); 735 | goto restart; 736 | 737 | #if 0 738 | strcpy (str,"Wall list overflow at LE:"); 739 | itoa(level,num,10); 740 | strcat (str,num); 741 | strcat (str," X:"); 742 | ltoa(objlist[0].x,num,10); 743 | strcat (str,num); 744 | strcat (str," Y:"); 745 | ltoa(objlist[0].y,num,10); 746 | strcat (str,num); 747 | strcat (str," AN:"); 748 | itoa(objlist[0].angle,num,10); 749 | strcat (str,num); 750 | 751 | Quit (str); 752 | #endif 753 | } 754 | 755 | // 756 | // proceed along wall 757 | // 758 | 759 | edgex = ((int32_t)tile.x<<16)+point2x[wallon]; 760 | edgey = ((int32_t)tile.y<<16)+point2y[wallon]; 761 | 762 | if (BackTrace(1)) // went behind a closer wall 763 | continue; 764 | 765 | // 766 | // advance to next tile along wall 767 | // 768 | tile.x += followx[wallon]; 769 | tile.y += followy[wallon]; 770 | 771 | if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]]) 772 | { 773 | InsideCorner (); // turn at a corner 774 | continue; 775 | } 776 | 777 | newcolor = tilemap[tile.x][tile.y]; 778 | 779 | if (!newcolor) // turn around an edge 780 | { 781 | OutsideCorner (); 782 | continue; 783 | } 784 | 785 | if (newcolor != basecolor) 786 | { 787 | // 788 | // wall changed color, so draw what we have and continue following 789 | // 790 | FinishWall (); 791 | rightwall->x1 = oldwall->x2; // new wall shares this edge 792 | rightwall->height1 = oldwall->height2; 793 | rightwall->wx0 = oldwall->wx1; 794 | rightwall->wz0 = oldwall->wz1; 795 | basecolor = newcolor; 796 | 797 | continue; 798 | } 799 | 800 | 801 | } while (tile.x != right.x || tile.y != right.y); 802 | 803 | 804 | 805 | //###################### 806 | // 807 | // draw the last tile 808 | // 809 | //###################### 810 | 811 | edgex = ((int32_t)tile.x<<16)+point2x[wallon]; 812 | edgey = ((int32_t)tile.y<<16)+point2y[wallon]; 813 | FinishWall(); 814 | 815 | wallon = cornerwall[wallon]; 816 | 817 | // 818 | // if the corner wall is visable, draw it 819 | // 820 | if (tile.yfocal.x) 829 | offset += 2; 830 | 831 | if (visable[offset][wallon]) 832 | { 833 | rightwall->x1 = oldwall->x2; // common edge with last wall 834 | rightwall->height1 = oldwall->height2; 835 | rightwall->wx0 = oldwall->wx1; 836 | rightwall->wz0 = oldwall->wz1; 837 | edgex = ((int32_t)tile.x<<16)+point2x[wallon]; 838 | edgey = ((int32_t)tile.y<<16)+point2y[wallon]; 839 | FinishWall(); 840 | } 841 | 842 | } 843 | 844 | //=========================================================================== 845 | -------------------------------------------------------------------------------- /IDLIBC_SDL.C: -------------------------------------------------------------------------------- 1 | 2 | #include "IDLIB.H" 3 | #include "JM_SB.H" 4 | 5 | #define SAMPLERATE 44100 6 | #define SAMPLES (SAMPLERATE/70) 7 | 8 | int SPKinterval; 9 | float SampleStep; 10 | 11 | static void MyAudioCallback(void *userdata, Uint8 *stream, int len); 12 | 13 | SDL_Window * window; 14 | int windowFullscreen; 15 | int windowWidth, windowHeight; 16 | int viewportX, viewportY, viewportWidth, viewportHeight; 17 | 18 | int processedevents = 0; 19 | 20 | int _NBKscan,_NBKascii; 21 | char _keydown[128]; 22 | char key[8],keyB1,keyB2; 23 | int32_t highscore; 24 | int level,bestlevel; 25 | 26 | SDL_GameController * controller; 27 | 28 | memptr soundseg; 29 | 30 | void IDLIBC_GL_Init(); 31 | 32 | #define ASPECT (320.f/240.f) 33 | 34 | void UpdateWindow() 35 | { 36 | float aspect = windowWidth / (float)windowHeight; 37 | if (aspect > ASPECT) 38 | { 39 | viewportWidth = windowHeight * 0.95f * ASPECT; 40 | viewportHeight = windowHeight * 0.95f; 41 | } 42 | else 43 | { 44 | viewportWidth = windowWidth * 0.95f; 45 | viewportHeight = windowWidth * 0.95f / ASPECT; 46 | } 47 | viewportX = (windowWidth - viewportWidth)/2; 48 | viewportY = (windowHeight - viewportHeight)/2; 49 | } 50 | 51 | void IDLIBC_SDL_Init() 52 | { 53 | SDL_Init(SDL_INIT_EVERYTHING);//SDL_INIT_VIDEO|SDL_INIT_GAMECONTROLLER); 54 | 55 | int x = SDL_WINDOWPOS_UNDEFINED; 56 | int y = SDL_WINDOWPOS_UNDEFINED; 57 | int w = 1024;//960;//1280; 58 | int h = 768;//720; 59 | viewportX = 0; 60 | viewportY = 0; 61 | windowWidth = w; 62 | windowHeight = h; 63 | 64 | Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; 65 | #ifndef _DEBUG 66 | flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; 67 | windowFullscreen = 1; 68 | #else 69 | windowFullscreen = 0; 70 | #endif 71 | 72 | window = SDL_CreateWindow("SDL Hovertank", x, y, w, h, flags); 73 | SDL_ShowCursor(SDL_DISABLE); 74 | SDL_GetWindowSize(window, &windowWidth, &windowHeight); 75 | UpdateWindow(); 76 | 77 | IDLIBC_GL_Init(); 78 | 79 | SDL_AudioSpec desired; 80 | SDL_AudioSpec audiospec; 81 | desired.freq = SAMPLERATE; 82 | desired.format = AUDIO_S16; 83 | desired.channels = 1; 84 | desired.samples = SAMPLES*2; 85 | desired.callback = MyAudioCallback; 86 | desired.userdata = NULL; 87 | if (SDL_OpenAudio(&desired, &audiospec) != 0) {assert(0);} 88 | 89 | SDL_Log("freq %d", audiospec.freq); 90 | SDL_Log("format %d", audiospec.format); 91 | SDL_Log("channels %d", audiospec.channels); 92 | SDL_Log("samples %d", audiospec.samples); 93 | 94 | SPKinterval = audiospec.freq/140; 95 | SampleStep = 1.f/audiospec.freq; 96 | 97 | SDL_PauseAudio(0); 98 | } 99 | 100 | #define sc_None 0 101 | #define sc_Bad 0xff 102 | #define sc_Return 0x1c 103 | #define sc_Enter sc_Return 104 | #define sc_Escape 0x01 105 | #define sc_Space 0x39 106 | #define sc_BackSpace 0x0e 107 | #define sc_Tab 0x0f 108 | #define sc_Alt 0x38 109 | #define sc_Control 0x1d 110 | #define sc_CapsLock 0x3a 111 | #define sc_LShift 0x2a 112 | #define sc_RShift 0x36 113 | #define sc_UpArrow 0x48 114 | #define sc_DownArrow 0x50 115 | #define sc_LeftArrow 0x4b 116 | #define sc_RightArrow 0x4d 117 | #define sc_Insert 0x52 118 | #define sc_Delete 0x53 119 | #define sc_Home 0x47 120 | #define sc_End 0x4f 121 | #define sc_PgUp 0x49 122 | #define sc_PgDn 0x51 123 | #define sc_F1 0x3b 124 | #define sc_F2 0x3c 125 | #define sc_F3 0x3d 126 | #define sc_F4 0x3e 127 | #define sc_F5 0x3f 128 | #define sc_F6 0x40 129 | #define sc_F7 0x41 130 | #define sc_F8 0x42 131 | #define sc_F9 0x43 132 | #define sc_F10 0x44 133 | #define sc_F11 0x57 134 | #define sc_F12 0x59 135 | 136 | #define sc_A 0x1e 137 | #define sc_B 0x30 138 | #define sc_C 0x2e 139 | #define sc_D 0x20 140 | #define sc_E 0x12 141 | #define sc_F 0x21 142 | #define sc_G 0x22 143 | #define sc_H 0x23 144 | #define sc_I 0x17 145 | #define sc_J 0x24 146 | #define sc_K 0x25 147 | #define sc_L 0x26 148 | #define sc_M 0x32 149 | #define sc_N 0x31 150 | #define sc_O 0x18 151 | #define sc_P 0x19 152 | #define sc_Q 0x10 153 | #define sc_R 0x13 154 | #define sc_S 0x1f 155 | #define sc_T 0x14 156 | #define sc_U 0x16 157 | #define sc_V 0x2f 158 | #define sc_W 0x11 159 | #define sc_X 0x2d 160 | #define sc_Y 0x15 161 | #define sc_Z 0x2c 162 | 163 | static int translateKey(int Sym) { 164 | switch (Sym) { 165 | default: return 0; break; 166 | case SDLK_RETURN: return sc_Return; break; 167 | case SDLK_ESCAPE: return sc_Escape; break; 168 | case SDLK_SPACE: return sc_Space; break; 169 | case SDLK_BACKSPACE: return sc_BackSpace; break; 170 | case SDLK_TAB: return sc_Tab; break; 171 | case SDLK_LALT: return sc_Alt; break; 172 | case SDLK_RALT: return sc_Alt; break; 173 | case SDLK_LCTRL: return sc_Control; break; 174 | case SDLK_RCTRL: return sc_Control; break; 175 | case SDLK_LSHIFT: return sc_LShift; break; 176 | case SDLK_RSHIFT: return sc_RShift; break; 177 | case SDLK_CAPSLOCK: return sc_CapsLock; break; 178 | 179 | case SDLK_UP: return sc_UpArrow; break; 180 | case SDLK_DOWN: return sc_DownArrow; break; 181 | case SDLK_LEFT: return sc_LeftArrow; break; 182 | case SDLK_RIGHT: return sc_RightArrow; break; 183 | 184 | case SDLK_PAGEUP: return sc_PgUp; break; 185 | case SDLK_PAGEDOWN: return sc_PgDn; break; 186 | case SDLK_INSERT: return sc_Insert; break; 187 | case SDLK_DELETE: return sc_Delete; break; 188 | case SDLK_HOME: return sc_Home; break; 189 | case SDLK_END: return sc_End; break; 190 | case SDLK_F1: return sc_F1; break; 191 | case SDLK_F2: return sc_F2; break; 192 | case SDLK_F3: return sc_F3; break; 193 | case SDLK_F4: return sc_F4; break; 194 | case SDLK_F5: return sc_F5; break; 195 | case SDLK_F6: return sc_F6; break; 196 | case SDLK_F7: return sc_F7; break; 197 | case SDLK_F8: return sc_F8; break; 198 | case SDLK_F9: return sc_F9; break; 199 | case SDLK_F10: return sc_F10; break; 200 | case SDLK_F11: return sc_F11; break; 201 | case SDLK_F12: return sc_F12; break; 202 | case SDLK_1: return 2; break; 203 | case SDLK_2: return 3; break; 204 | case SDLK_3: return 4; break; 205 | case SDLK_4: return 5; break; 206 | case SDLK_5: return 6; break; 207 | case SDLK_6: return 7; break; 208 | case SDLK_7: return 8; break; 209 | case SDLK_8: return 9; break; 210 | case SDLK_9: return 10; break; 211 | case SDLK_0: return 11; break; 212 | case SDLK_a: return sc_A; break; 213 | case SDLK_b: return sc_B; break; 214 | case SDLK_c: return sc_C; break; 215 | case SDLK_d: return sc_D; break; 216 | case SDLK_e: return sc_E; break; 217 | case SDLK_f: return sc_F; break; 218 | case SDLK_g: return sc_G; break; 219 | case SDLK_h: return sc_H; break; 220 | case SDLK_i: return sc_I; break; 221 | case SDLK_j: return sc_J; break; 222 | case SDLK_k: return sc_K; break; 223 | case SDLK_l: return sc_L; break; 224 | case SDLK_m: return sc_M; break; 225 | case SDLK_n: return sc_N; break; 226 | case SDLK_o: return sc_O; break; 227 | case SDLK_p: return sc_P; break; 228 | case SDLK_q: return sc_Q; break; 229 | case SDLK_r: return sc_R; break; 230 | case SDLK_s: return sc_S; break; 231 | case SDLK_t: return sc_T; break; 232 | case SDLK_u: return sc_U; break; 233 | case SDLK_v: return sc_V; break; 234 | case SDLK_w: return sc_W; break; 235 | case SDLK_x: return sc_X; break; 236 | case SDLK_y: return sc_Y; break; 237 | case SDLK_z: return sc_Z; break; 238 | } 239 | } 240 | 241 | void ProcessEvent(SDL_Event * event) 242 | { 243 | switch(event->type) 244 | { 245 | case SDL_QUIT: 246 | exit(0); 247 | break; 248 | case SDL_WINDOWEVENT: 249 | switch (event->window.event) { 250 | case SDL_WINDOWEVENT_SIZE_CHANGED: 251 | windowWidth = event->window.data1; 252 | windowHeight = event->window.data2; 253 | UpdateWindow(); 254 | break; 255 | } 256 | break; 257 | case SDL_KEYDOWN: 258 | if (event->key.keysym.sym == SDLK_RETURN && event->key.keysym.mod & KMOD_ALT) 259 | { 260 | int flags = windowFullscreen? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP; 261 | if (SDL_SetWindowFullscreen(window, flags) == 0) 262 | { 263 | windowFullscreen = 1 - windowFullscreen; 264 | UpdateWindow(); 265 | } 266 | return; 267 | } 268 | _NBKscan = translateKey(event->key.keysym.sym); 269 | _keydown[_NBKscan] = 1; 270 | if (event->key.keysym.mod & KMOD_SHIFT) 271 | { 272 | _NBKscan |= 0x80; 273 | } 274 | if (event->key.keysym.sym >= SDLK_0 && event->key.keysym.sym <= SDLK_9) 275 | { 276 | _NBKascii = '0' + (event->key.keysym.sym - SDLK_0); 277 | } 278 | else if (event->key.keysym.sym >= SDLK_a && event->key.keysym.sym <= SDLK_z) 279 | { 280 | if (event->key.keysym.mod & KMOD_SHIFT) 281 | { 282 | _NBKascii = 'A' + (event->key.keysym.sym - SDLK_a); 283 | } 284 | else 285 | { 286 | _NBKascii = 'a' + (event->key.keysym.sym - SDLK_a); 287 | } 288 | } 289 | else 290 | { 291 | switch (event->key.keysym.sym) 292 | { 293 | case SDLK_RETURN: _NBKascii = '\r'; break; 294 | case SDLK_BACKSPACE: _NBKascii = 8; break; 295 | case SDLK_DELETE: _NBKascii = 127; break; 296 | case SDLK_SPACE: _NBKascii = ' '; break; 297 | case SDLK_ESCAPE: _NBKascii = 27; break; 298 | } 299 | } 300 | break; 301 | case SDL_KEYUP: 302 | _keydown[translateKey(event->key.keysym.sym)] = 0; 303 | break; 304 | } 305 | } 306 | 307 | void CheckGamepad() 308 | { 309 | if (controller && SDL_GameControllerGetAttached(controller)) 310 | { 311 | return; 312 | } 313 | 314 | static int check = 0; 315 | check++; 316 | if (check < 30) 317 | { 318 | return; 319 | } 320 | 321 | check = 0; 322 | int numJoysticks = SDL_NumJoysticks(); 323 | for (int i = 0; i < numJoysticks; ++i) 324 | { 325 | if (!SDL_IsGameController(i)) 326 | { 327 | continue; 328 | } 329 | controller = SDL_GameControllerOpen(i); 330 | if (controller) 331 | { 332 | break; 333 | } 334 | } 335 | } 336 | 337 | void ReadJoystick (int joynum,int *xcount,int *ycount) 338 | { 339 | CheckGamepad(); 340 | *xcount = 501; 341 | *ycount = 501; 342 | if (controller) 343 | { 344 | int leftx = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); 345 | int lefty = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); 346 | *xcount = ((int)leftx+32768)*500/65536; 347 | *ycount = ((int)lefty+32768)*500/65536; 348 | } 349 | } 350 | 351 | void IN_Poll() 352 | { 353 | SDL_Event event; 354 | while(SDL_PollEvent(&event)) { 355 | ProcessEvent(&event); 356 | } 357 | } 358 | 359 | // a lighter version for those spamming keydown, NBKscan, NBKascii 360 | void IN_PollSingle() 361 | { 362 | SDL_Event event; 363 | if (SDL_PollEvent(&event)) { 364 | ProcessEvent(&event); 365 | } 366 | } 367 | 368 | char * GetKeyDown(void) 369 | { 370 | IN_PollSingle(); 371 | return _keydown; 372 | } 373 | 374 | int GetNBKscan(void) 375 | { 376 | IN_PollSingle(); 377 | return _NBKscan; 378 | } 379 | 380 | int GetNBKascii(void) 381 | { 382 | IN_PollSingle(); 383 | return _NBKascii; 384 | } 385 | 386 | void ClearKeys (void) 387 | { 388 | _NBKscan=_NBKascii=0; 389 | memset (_keydown,0,sizeof(_keydown)); 390 | } 391 | 392 | 393 | void Ack() 394 | { 395 | VideoSync(); 396 | while (1) 397 | { 398 | SDL_Event event; 399 | while(SDL_PollEvent(&event)) { 400 | ProcessEvent(&event); 401 | if (event.type == SDL_KEYDOWN) 402 | { 403 | return; 404 | } 405 | } 406 | } 407 | } 408 | 409 | 410 | int NoBiosKey(int x) 411 | { 412 | processedevents = 1; 413 | if (x) 414 | { 415 | SDL_Event event; 416 | while(SDL_PollEvent(&event)) { 417 | ProcessEvent(&event); 418 | if (event.type == SDL_KEYDOWN) 419 | { 420 | return (_NBKscan<<8)|_NBKascii; 421 | } 422 | } 423 | return 0; 424 | } 425 | SDL_Event event; 426 | while(SDL_PollEvent(&event)) { 427 | ProcessEvent(&event); 428 | if (event.type == SDL_KEYUP) 429 | { 430 | break; 431 | } 432 | if (event.type == SDL_KEYDOWN) 433 | { 434 | break; 435 | } 436 | } 437 | return (_NBKscan<<8)|_NBKascii; 438 | } 439 | 440 | void WaitVBL(int num) 441 | { 442 | int starttime = inttime; 443 | VideoSync(); 444 | num*=2; 445 | while (inttime-starttime < num) {} 446 | if (processedevents) 447 | { 448 | processedevents = 0; 449 | } 450 | else 451 | { 452 | IN_Poll(); 453 | } 454 | } 455 | 456 | 457 | 458 | //////////////////////// 459 | // 460 | // loadctrls 461 | // Tries to load the control panel settings 462 | // creates a default if not present 463 | // 464 | //////////////////////// 465 | 466 | void LoadCtrls (void) 467 | { 468 | FILE *handle; 469 | 470 | if (!(handle = fopen("CTLPANEL."EXTENSION, "rb"))) 471 | // 472 | // set up default control panel settings 473 | // 474 | { 475 | key[0] = 0x48; 476 | key[1] = 0x49; 477 | key[2] = 0x4d; 478 | key[3] = 0x51; 479 | key[4] = 0x50; 480 | key[5] = 0x4f; 481 | key[6] = 0x4b; 482 | key[7] = 0x47; 483 | keyB1 = 0x1d; 484 | keyB2 = 0x38; 485 | } 486 | else 487 | { 488 | fread(&key, 1, sizeof(key), handle); 489 | fread(&keyB1, 1, sizeof(keyB1), handle); 490 | fread(&keyB2, 1, sizeof(keyB2), handle); 491 | fread(&highscore, 1, sizeof(highscore), handle); 492 | fread(&bestlevel, 1, sizeof(bestlevel), handle); 493 | fclose(handle); 494 | } 495 | } 496 | 497 | void SaveCtrls (void) 498 | { 499 | FILE * handle; 500 | 501 | if (!(handle = fopen("CTLPANEL."EXTENSION, "wb"))) 502 | return; 503 | 504 | fwrite(&key, 1, sizeof(key), handle); 505 | fwrite(&keyB1, 1, sizeof(keyB1), handle); 506 | fwrite(&keyB2, 1, sizeof(keyB2), handle); 507 | fwrite(&highscore, 1, sizeof(highscore), handle); 508 | fwrite(&bestlevel, 1, sizeof(bestlevel), handle); 509 | 510 | fclose(handle); 511 | } 512 | 513 | //========================================================================= 514 | 515 | /* 516 | =========================== 517 | = 518 | = ControlKBD 519 | = 520 | =========================== 521 | */ 522 | 523 | ControlStruct ControlKBD () 524 | { 525 | int xmove=0, 526 | ymove=0; 527 | ControlStruct action; 528 | 529 | IN_Poll(); 530 | 531 | if (_keydown [key[north]]) 532 | ymove=-1; 533 | if (_keydown [key[east]]) 534 | xmove=1; 535 | if (_keydown [key[south]]) 536 | ymove=1; 537 | if (_keydown [key[west]]) 538 | xmove=-1; 539 | 540 | if (_keydown [key[northeast]]) 541 | { 542 | ymove=-1; 543 | xmove=1; 544 | } 545 | if (_keydown [key[northwest]]) 546 | { 547 | ymove=-1; 548 | xmove=-1; 549 | } 550 | if (_keydown [key[southeast]]) 551 | { 552 | ymove=1; 553 | xmove=1; 554 | } 555 | if (_keydown [key[southwest]]) 556 | { 557 | ymove=1; 558 | xmove=-1; 559 | } 560 | 561 | switch (ymove*3+xmove) 562 | { 563 | case -4: action.dir = northwest; break; 564 | case -3: action.dir = north; break; 565 | case -2: action.dir = northeast; break; 566 | case -1: action.dir = west; break; 567 | case 0: action.dir = nodir; break; 568 | case 1: action.dir = east; break; 569 | case 2: action.dir = southwest; break; 570 | case 3: action.dir = south; break; 571 | case 4: action.dir = southeast; break; 572 | } 573 | 574 | action.button1 = _keydown [keyB1]; 575 | action.button2 = _keydown [keyB2]; 576 | 577 | return (action); 578 | } 579 | 580 | /* 581 | ============================= 582 | = 583 | = ControlJoystick (joy# = 1 / 2) 584 | = 585 | ============================= 586 | */ 587 | 588 | extern int JoyXlow [3], JoyXhigh [3], JoyYlow [3], JoyYhigh [3], buttonflip; 589 | 590 | ControlStruct ControlJoystick (int joynum) 591 | { 592 | int joyx = 0,joyy = 0, /* resistance in joystick */ 593 | xmove = 0, 594 | ymove = 0, 595 | buttons; 596 | ControlStruct action; 597 | 598 | IN_Poll(); 599 | CheckGamepad(); 600 | 601 | ReadJoystick (joynum,&joyx,&joyy); 602 | if ( (joyx>500) | (joyy>500) ) 603 | { 604 | joyx=JoyXlow [joynum] + 1; /* no joystick connected, do nothing */ 605 | joyy=JoyYlow [joynum] + 1; 606 | } 607 | 608 | if (joyx > JoyXhigh [joynum]) 609 | xmove = 1; 610 | else if (joyx < JoyXlow [joynum]) 611 | xmove = -1; 612 | if (joyy > JoyYhigh [joynum]) 613 | ymove = 1; 614 | else if (joyy < JoyYlow [joynum]) 615 | ymove = -1; 616 | 617 | switch (ymove*3+xmove) 618 | { 619 | case -4: action.dir = northwest; break; 620 | case -3: action.dir = north; break; 621 | case -2: action.dir = northeast; break; 622 | case -1: action.dir = west; break; 623 | case 0: action.dir = nodir; break; 624 | case 1: action.dir = east; break; 625 | case 2: action.dir = southwest; break; 626 | case 3: action.dir = south; break; 627 | case 4: action.dir = southeast; break; 628 | } 629 | 630 | #if 0 631 | buttons = inportb (0x201); /* Get all four button status */ 632 | if (joynum == 1) 633 | { 634 | action.button1 = ((buttons & 0x10) == 0); 635 | action.button2 = ((buttons & 0x20) == 0); 636 | } 637 | else 638 | { 639 | action.button1 = ((buttons & 0x40) == 0); 640 | action.button2 = ((buttons & 0x80) == 0); 641 | } 642 | #endif 643 | float rightz = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / 32768.f; 644 | if (rightz > 0.5f) 645 | { 646 | action.button1 = 1; 647 | } 648 | else 649 | { 650 | action.button1 = 0; 651 | } 652 | float leftz = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / 32768.f; 653 | if (leftz > 0.5f) 654 | { 655 | action.button2 = 1; 656 | } 657 | else 658 | { 659 | action.button2 = 0; 660 | } 661 | if (buttonflip) 662 | { 663 | buttons = action.button1; 664 | action.button1 = action.button2; 665 | action.button2 = buttons; 666 | } 667 | return (action); 668 | } 669 | 670 | 671 | 672 | ControlStruct ControlPlayer (int player) 673 | { 674 | ControlStruct ret; 675 | 676 | switch (playermode[player]) 677 | { 678 | case keyboard : return ControlKBD (); 679 | case joystick1: return ControlJoystick(1); 680 | case joystick2: return ControlJoystick(2); 681 | } 682 | 683 | return ControlKBD(); 684 | #if 0 685 | int xmove=0, 686 | ymove=0; 687 | ControlStruct action; 688 | 689 | IN_Poll(); 690 | 691 | if (_keydown [key[north]]) 692 | ymove=-1; 693 | if (_keydown [key[east]]) 694 | xmove=1; 695 | if (_keydown [key[south]]) 696 | ymove=1; 697 | if (_keydown [key[west]]) 698 | xmove=-1; 699 | 700 | if (_keydown [key[northeast]]) 701 | { 702 | ymove=-1; 703 | xmove=1; 704 | } 705 | if (_keydown [key[northwest]]) 706 | { 707 | ymove=-1; 708 | xmove=-1; 709 | } 710 | if (_keydown [key[southeast]]) 711 | { 712 | ymove=1; 713 | xmove=1; 714 | } 715 | if (_keydown [key[southwest]]) 716 | { 717 | ymove=1; 718 | xmove=-1; 719 | } 720 | 721 | action.button1 = 0; 722 | action.button2 = 0; 723 | 724 | CheckGamepad(); 725 | if (controller) 726 | { 727 | //float leftx = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) / 32768.f; 728 | float lefty = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) / 32768.f; 729 | //float rightx = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) / 32768.f; 730 | float righty = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) / 32768.f; 731 | if (lefty < -0.1f) 732 | { 733 | if (righty < -0.1f) 734 | { 735 | ymove = -1; 736 | } 737 | else if (righty > 0.1f) 738 | { 739 | xmove = 1; 740 | } 741 | } 742 | else if (lefty > 0.1f) 743 | { 744 | if (righty < -0.1f) 745 | { 746 | xmove = -1; 747 | } 748 | else if (righty > 0.1f) 749 | { 750 | ymove = 1; 751 | } 752 | } 753 | float rightz = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / 32768.f; 754 | if (rightz > 0.5f) action.button1 = 1; 755 | float leftz = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / 32768.f; 756 | if (leftz > 0.5f) action.button2 = 1; 757 | } 758 | 759 | switch (ymove*3+xmove) 760 | { 761 | case -4: action.dir = northwest; break; 762 | case -3: action.dir = north; break; 763 | case -2: action.dir = northeast; break; 764 | case -1: action.dir = west; break; 765 | case 0: action.dir = nodir; break; 766 | case 1: action.dir = east; break; 767 | case 2: action.dir = southwest; break; 768 | case 3: action.dir = south; break; 769 | case 4: action.dir = southeast; break; 770 | } 771 | 772 | action.button1 |= _keydown [keyB1]; 773 | action.button2 |= _keydown [keyB2]; 774 | 775 | return (action); 776 | #endif 777 | } 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | int *UpdateIntTime() 786 | { 787 | static int lastTime = 0; 788 | static int _inttime = 0; 789 | int newTime = SDL_GetTicks()*140/1000; 790 | _inttime += (newTime - lastTime); 791 | lastTime = newTime; 792 | return &_inttime; 793 | } 794 | 795 | 796 | int SPKfreq; 797 | 798 | //#define SoundLog SDL_Log 799 | #define SoundLog(...) 800 | 801 | void _sound(int _frequency) 802 | { 803 | //if (_frequency != SPKfreq) 804 | { 805 | SoundLog("freq %d",_frequency); 806 | } 807 | SPKfreq = _frequency; 808 | } 809 | 810 | void _nosound() 811 | { 812 | //if (0 != SPKfreq) 813 | { 814 | SoundLog("freq 0"); 815 | } 816 | SPKfreq = 0; 817 | } 818 | 819 | void sound(int _frequency) 820 | { 821 | SDL_LockAudio(); 822 | _sound(_frequency); 823 | SDL_UnlockAudio(); 824 | } 825 | 826 | void nosound(void) 827 | { 828 | SDL_LockAudio(); 829 | _sound(0); 830 | SDL_UnlockAudio(); 831 | } 832 | 833 | int dontplay = 0; 834 | int soundmode = 1; // 0=nosound, 1=SPKR, 2= adlib... 835 | int soundblaster = 1; 836 | byte SndPriority; 837 | short * SndPtr; 838 | 839 | void _PlaySound(int soundnum) 840 | { 841 | spksndtype * sound = ((spksndtype*)soundseg) + soundnum; 842 | 843 | if (dontplay || soundmode == 0) return; 844 | if (sound->priority < SndPriority) 845 | { 846 | SoundLog(" rejected lower priority"); 847 | return; 848 | } 849 | else if (SndPtr) 850 | { 851 | SoundLog(" replaced sound"); 852 | } 853 | 854 | SndPriority = sound->priority; 855 | 856 | if (soundblaster) 857 | { 858 | jmPlaySample(soundnum); 859 | return; 860 | } 861 | 862 | SndPtr = (short*)(((char*)soundseg) + sound->start); 863 | } 864 | 865 | void PlaySound(int soundnum) 866 | { 867 | SoundLog("PlaySound %d", soundnum); 868 | SDL_LockAudio(); 869 | _PlaySound(soundnum); 870 | SDL_UnlockAudio(); 871 | } 872 | 873 | void _StopSound(void) 874 | { 875 | SoundLog("StopSound"); 876 | if (dontplay) return; 877 | 878 | SndPriority = 0; 879 | 880 | if (soundblaster) 881 | { 882 | jmStopSample(); 883 | return; 884 | } 885 | 886 | SndPtr = 0; 887 | _nosound(); 888 | } 889 | 890 | void StopSound(void) 891 | { 892 | SDL_LockAudio(); 893 | StopSound(); 894 | SDL_UnlockAudio(); 895 | } 896 | 897 | int SoundPlaying (void) 898 | { 899 | if (soundblaster) 900 | return jmSamplePlaying(); 901 | else 902 | return SndPtr != 0; 903 | } 904 | 905 | void UpdateSPKR() 906 | { 907 | if (!SndPtr) 908 | { 909 | _nosound(); 910 | return; 911 | } 912 | short freq = *SndPtr; 913 | SndPtr += 1; 914 | if (freq == 0) 915 | { 916 | _nosound(); 917 | return; 918 | } 919 | if (freq == -1) 920 | { 921 | _StopSound(); 922 | return; 923 | } 924 | if (soundmode == 0) 925 | { 926 | _nosound(); 927 | return; 928 | } 929 | _sound(1193180/freq); 930 | } 931 | 932 | int SPKupdate; 933 | float SPKpulse; 934 | float SPKpos; 935 | float SPKvel; 936 | float SPKspeed = 1000.f/60.f/44100.f; 937 | 938 | static void MyAudioCallback(void *userdata, Uint8 *stream, int len) 939 | { 940 | memset(stream, 0, len); 941 | 942 | if (soundmode != 1) 943 | { 944 | return; 945 | } 946 | 947 | short * stream16 = (short*)stream; 948 | 949 | if (soundblaster && jmData) 950 | { 951 | for (int i = 0; i < len/2; i++) 952 | { 953 | #if 1 954 | int offset = (int)(jmDataTime*jmDataFreq); 955 | if (offset >= jmDataLength) 956 | { 957 | jmStopSample(); 958 | break; 959 | } 960 | int sample = (((int)jmData[offset]) - 127)*256; 961 | #else 962 | // linear interpolation 963 | float foffset = jmDataTime*jmDataFreq; 964 | int offset = foffset; 965 | if (offset+1 >= jmDataLength) 966 | { 967 | jmStopSample(); 968 | break; 969 | } 970 | float finterp = fmod(foffset, 1.f)*256.f; 971 | int sample1 = (float)jmData[offset]; 972 | int sample2 = (float)jmData[offset+1]; 973 | int sample = (int)(sample1*(256.f-finterp) + sample2*finterp) - 32768; 974 | #endif 975 | *stream16 = (short)sample; 976 | jmDataTime += SampleStep; 977 | stream16++; 978 | } 979 | } 980 | 981 | for (int i = 0; i < len/2; i++) 982 | { 983 | if (SPKupdate >= SPKinterval) 984 | { 985 | if (SndPtr) 986 | { 987 | UpdateSPKR(); 988 | } 989 | SPKupdate = 0; 990 | } 991 | else 992 | { 993 | SPKupdate++; 994 | } 995 | if (SPKfreq) 996 | { 997 | // square wave 998 | int sample = (1&(int)SPKpulse)*65535 - 32768; 999 | SPKpulse += SampleStep*SPKfreq*2; 1000 | *stream16 += sample; 1001 | } 1002 | stream16++; 1003 | } 1004 | } 1005 | 1006 | -------------------------------------------------------------------------------- /IDLIBC_GL.C: -------------------------------------------------------------------------------- 1 | 2 | #include "IDLIB.H" 3 | #include "IDLIB_SDL.H" 4 | 5 | // to use macro convenience 6 | #define PFNglGenFramebuffersPROC PFNGLGENFRAMEBUFFERSPROC 7 | #define PFNglGenRenderbuffersPROC PFNGLGENRENDERBUFFERSPROC 8 | #define PFNglBindRenderbufferPROC PFNGLBINDRENDERBUFFERPROC 9 | #define PFNglRenderbufferStoragePROC PFNGLRENDERBUFFERSTORAGEPROC 10 | #define PFNglBindFramebufferPROC PFNGLBINDFRAMEBUFFERPROC 11 | #define PFNglFramebufferTexturePROC PFNGLFRAMEBUFFERTEXTUREPROC 12 | #define PFNglFramebufferRenderbufferPROC PFNGLFRAMEBUFFERRENDERBUFFERPROC 13 | #define PFNglCheckFramebufferStatusPROC PFNGLCHECKFRAMEBUFFERSTATUSPROC 14 | 15 | // use the convenient macros 16 | GLDEFINE(glGenFramebuffers); 17 | GLDEFINE(glGenRenderbuffers); 18 | GLDEFINE(glBindRenderbuffer); 19 | GLDEFINE(glRenderbufferStorage); 20 | GLDEFINE(glBindFramebuffer); 21 | GLDEFINE(glFramebufferTexture); 22 | GLDEFINE(glFramebufferRenderbuffer); 23 | GLDEFINE(glCheckFramebufferStatus); 24 | 25 | #define NUMFRAMEBUFFERS 4 26 | typedef struct { 27 | GLuint frameBuffer[NUMFRAMEBUFFERS]; 28 | GLuint texture[NUMFRAMEBUFFERS]; 29 | GLuint renderBuffer[NUMFRAMEBUFFERS]; 30 | int width; 31 | int height; 32 | } framebuffer_t; 33 | 34 | framebuffer_t fbo; 35 | 36 | matrix4x4_t matProj2D; 37 | matrix4x4_t matProj; 38 | 39 | unsigned screenofs; 40 | unsigned int linewidth; 41 | 42 | 43 | 44 | typedef struct { 45 | int index; 46 | int xoffset; 47 | int yoffset; 48 | } video_fbo_t; 49 | 50 | float video_fade = 1; 51 | int video_split = 200; 52 | int video_crtc = 0; 53 | int video_pel = 0; 54 | int video_line_width = 40; 55 | video_fbo_t video_fbo = {0}; 56 | 57 | int video_screenofs_fbo; 58 | unsigned video_oldscreenofs; 59 | int video_baseofs; 60 | int video_screenofs_x; 61 | int video_screenofs_y; 62 | 63 | void GetAddressInfo(int address, int * base, int * fbo_index) 64 | { 65 | if (video_line_width == 80) 66 | { 67 | if (address <= 80*200) 68 | { 69 | *base = 0; 70 | *fbo_index = 0; 71 | return; 72 | } 73 | if (address >= 0x4000 && address <= 0x4000+80*200) 74 | { 75 | *base = 0x4000; 76 | *fbo_index = 1; 77 | return; 78 | } 79 | if (address >= 0x8000 && address <= 0x8000+80*200) 80 | { 81 | *base = 0x8000; 82 | *fbo_index = 2; 83 | return; 84 | } 85 | } 86 | else if (video_line_width == 40) 87 | { 88 | if (address <= 40*200) 89 | { 90 | *base = 0; 91 | *fbo_index = 0; 92 | return; 93 | } 94 | if (address >= 0x3700 && address <= 0x3700+40*200) 95 | { 96 | *base = 0x3700; 97 | *fbo_index = 1; 98 | return; 99 | } 100 | if (address >= 0x7a00 && address <= 0x7a00+40*200) 101 | { 102 | *base = 0x7a00; 103 | *fbo_index = 2; 104 | return; 105 | } 106 | if (address >= 0xbd00 && address <= 0xbd00+40*200) 107 | { 108 | *base = 0xbd00; 109 | *fbo_index = 3; 110 | return; 111 | } 112 | } 113 | assert(0); // unknown address 114 | } 115 | 116 | memptr CreateTexture(int width, int height, const memptr planes, unsigned char background) 117 | { 118 | int plane_width = width; 119 | width *= 8; 120 | int size = width * height; 121 | 122 | unsigned int *data; 123 | MMGetPtr((memptr*)&data,size*4); 124 | 125 | unsigned char *plane0 = (unsigned char*)planes; 126 | unsigned char *plane1 = plane0 + plane_width*height; 127 | unsigned char *plane2 = plane1 + plane_width*height; 128 | unsigned char *plane3 = plane2 + plane_width*height; 129 | 130 | for (int y = 0; y < height; y++) 131 | { 132 | for (int x = 0; x < width; x+=8) 133 | { 134 | unsigned char by0 = plane0[y*plane_width+x/8]; 135 | unsigned char by1 = plane1[y*plane_width+x/8]; 136 | unsigned char by2 = plane2[y*plane_width+x/8]; 137 | unsigned char by3 = plane3[y*plane_width+x/8]; 138 | for (int b = 0; b < 8; b++) 139 | { 140 | unsigned char index = 141 | (((by0 >> (7-b))&1)<<0) | 142 | (((by1 >> (7-b))&1)<<1) | 143 | (((by2 >> (7-b))&1)<<2) | 144 | (((by3 >> (7-b))&1)<<3); 145 | if (index == background) 146 | { 147 | data[y*width+x+b] = 0; 148 | } 149 | else 150 | { 151 | data[y*width+x+b] = GetColor(index); 152 | } 153 | } 154 | } 155 | } 156 | 157 | gltexture *gltex; 158 | MMGetPtr((memptr*)&gltex, sizeof(*gltex)); 159 | gltex->width = width; 160 | gltex->height = height; 161 | glGenTextures(1, &gltex->texture); 162 | 163 | glBindTexture(GL_TEXTURE_2D, gltex->texture); 164 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 165 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 166 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 167 | 168 | MMFreePtr((memptr*)&data); 169 | 170 | return gltex; 171 | } 172 | 173 | 174 | 175 | #ifdef CreateFont 176 | #undef CreateFont 177 | #endif 178 | void CreateFont() 179 | { 180 | char * fontseg = (char*)grsegs[STARTFONT]; 181 | font_t * font = (font_t*)fontseg; 182 | 183 | int total_width = 0; 184 | for (int i = 0; i < 256; i++) 185 | { 186 | total_width += font->width[i]; 187 | } 188 | assert(total_width < 32768); 189 | int height = font->height; 190 | 191 | uint32_t * pixels; 192 | MMGetPtr((memptr*)&pixels, total_width*height*4); 193 | 194 | font_t * final_font; 195 | MMGetPtr((memptr*)&final_font, sizeof(font_t)); 196 | 197 | final_font->height = height; 198 | memcpy(final_font->width, font->width, sizeof(final_font->width)); 199 | final_font->total_width = total_width; 200 | 201 | int dx = 0; 202 | for (int i = 0; i < 256; i++) 203 | { 204 | final_font->location[i] = dx; 205 | int cwidth = font->width[i]; 206 | int csize = (font->width[i]+7)/8 * height; 207 | char *c = (char*)fontseg + font->location[i] + csize; // TEST 208 | int x, y, b; 209 | if (cwidth == 0) 210 | { 211 | continue; 212 | } 213 | for (y = 0; y < font->height; y++) 214 | { 215 | int yoffset = y*total_width; 216 | for (x = 0; x < cwidth; x+= 8) 217 | { 218 | int xyoffset = x + dx + yoffset; 219 | uint8_t bits = *c++; 220 | int bc = cwidth-x; 221 | if (bc > 8) bc = 8; 222 | for (b = 0; b < bc; b++) 223 | { 224 | int offset = xyoffset + b; 225 | assert(offset*4 < total_width*height*4); 226 | pixels[offset] = ((bits>>(7-b))&1)? 0xFFFFFFFF : 0; 227 | MMValidatePtr((memptr*)&pixels); 228 | } 229 | } 230 | } 231 | dx += cwidth; 232 | } 233 | 234 | GLuint texture; 235 | glGenTextures(1, &texture); 236 | glBindTexture(GL_TEXTURE_2D, texture); 237 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 238 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 239 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, total_width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 240 | final_font->texture = texture; 241 | 242 | MMFreePtr(&grsegs[STARTFONT]); 243 | grsegs[STARTFONT] = (memptr)final_font; 244 | 245 | MMFreePtr((memptr*)&pixels); 246 | } 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | int CreateFrameBuffers(framebuffer_t * fbo, int width, int height) 255 | { 256 | //glGenFramebuffers(NUMFRAMEBUFFERS, fbo->frameBuffer); 257 | //glGenTextures(NUMFRAMEBUFFERS, fbo->texture); 258 | //glGenRenderbuffers(NUMFRAMEBUFFERS, fbo->renderBuffer); 259 | fbo->width = width; 260 | fbo->height = height; 261 | 262 | for (int i = 0; i < NUMFRAMEBUFFERS; i++) 263 | { 264 | glGenFramebuffers(1, &fbo->frameBuffer[i]); 265 | glGenTextures(1, &fbo->texture[i]); 266 | glGenRenderbuffers(1, &fbo->renderBuffer[i]); 267 | 268 | // create texture 269 | glBindTexture(GL_TEXTURE_2D, fbo->texture[i]); 270 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 271 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 272 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 273 | 274 | // create render buffer 275 | glBindRenderbuffer(GL_RENDERBUFFER, fbo->renderBuffer[i]); 276 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); 277 | 278 | // attach everything 279 | glBindFramebuffer(GL_FRAMEBUFFER, fbo->frameBuffer[i]); 280 | glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fbo->texture[i], 0); 281 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->renderBuffer[i]); 282 | 283 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 284 | { 285 | assert(0); 286 | return 0; 287 | } 288 | } 289 | 290 | Matrix4x4_SetScreen(&matProj2D, (float)width, (float)height); 291 | 292 | return 1; 293 | } 294 | 295 | 296 | 297 | 298 | /* Source for the following is 299 | http://commons.wikimedia.org/w/index.php?title=File:EGA_Table.PNG&oldid=39767054 300 | */ 301 | static uint32_t EGAPalette[64] = { 302 | 0xFF000000, 0xFFAA0000, 0xFF00AA00, 0xFFAAAA00, // 0- 3 303 | 0xFF0000AA, 0xFFAA00AA, 0xFF00AAAA, 0xFFAAAAAA, // 4- 7 304 | 0xFF550000, 0xFFFF0000, 0xFF55AA00, 0xFFFFAA00, // 8-11 305 | 0xFF5500AA, 0xFFFF00AA, 0xFF55AAAA, 0xFFFFAAAA, // 12-15 306 | 307 | 0xFF005500, 0xFFAA5500, 0xFF00FF00, 0xFFAAFF00, // 16-19 308 | 0xFF0055AA, 0xFFAA55AA, 0xFF00FFAA, 0xFFAAFFAA, // 20-23 309 | 0xFF555500, 0xFFFF5500, 0xFF55FF00, 0xFFFFFF00, // 24-27 310 | 0xFF5555AA, 0xFFFF55AA, 0xFF55FFAA, 0xFFFFFFAA, // 28-31 311 | 312 | 0xFF000055, 0xFFAA0055, 0xFF00AA55, 0xFFAAAA55, // 32-35 313 | 0xFF0000FF, 0xFFAA00FF, 0xFF00AAFF, 0xFFAAAAFF, // 36-39 314 | 0xFF550055, 0xFFFF0055, 0xFF55AA55, 0xFFFFAA55, // 40-43 315 | 0xFF5500FF, 0xFFFF00FF, 0xFF55AAFF, 0xFFFFAAFF, // 44-47 316 | 317 | 0xFF005555, 0xFFAA5555, 0xFF00FF55, 0xFFAAFF55, // 48-51 318 | 0xFF0055FF, 0xFFAA55FF, 0xFF00FFFF, 0xFFAAFFFF, // 52-55 319 | 0xFF555555, 0xFFFF5555, 0xFF55FF55, 0xFFFFFF55, // 56-59 320 | 0xFF5555FF, 0xFFFF55FF, 0xFF55FFFF, 0xFFFFFFFF, // 60-63 321 | }; 322 | 323 | static int EGADefaultColors[16] = {0, 1, 2, 3, 4, 5, 20, 7, 56, 57, 58, 59, 60, 61, 62, 63}; 324 | 325 | unsigned int GetColor(int i) 326 | { 327 | return EGAPalette[EGADefaultColors[i&0xf]]; 328 | } 329 | 330 | void IDLIBC_GL_Init() 331 | { 332 | SDL_GLContext context = SDL_GL_CreateContext(window); 333 | 334 | SHADERS_Init(); 335 | 336 | GLGETPROC(glGenFramebuffers); 337 | GLGETPROC(glGenRenderbuffers); 338 | GLGETPROC(glBindRenderbuffer); 339 | GLGETPROC(glRenderbufferStorage); 340 | GLGETPROC(glBindFramebuffer); 341 | GLGETPROC(glFramebufferTexture); 342 | GLGETPROC(glFramebufferRenderbuffer); 343 | GLGETPROC(glCheckFramebufferStatus); 344 | 345 | if (!CreateFrameBuffers(&fbo, 1024, 256))//SCREENWIDTH*8*2, 200)) 346 | { 347 | SDL_Log("Error Creating Framebuffer"); 348 | assert(0); 349 | exit(0); 350 | } 351 | 352 | glBindFramebuffer(GL_FRAMEBUFFER, fbo.frameBuffer[0]); 353 | glViewport(0,0,fbo.width,fbo.height); 354 | } 355 | 356 | 357 | 358 | void SetScreenOfs() 359 | { 360 | if (screenofs == video_oldscreenofs) 361 | { 362 | return; 363 | } 364 | video_oldscreenofs = screenofs; 365 | 366 | int baseofs; 367 | GetAddressInfo(screenofs, &baseofs, &video_screenofs_fbo); 368 | 369 | int ofs = screenofs - baseofs; 370 | video_screenofs_x = (ofs%video_line_width)*8; 371 | video_screenofs_y = (ofs/video_line_width); 372 | if (baseofs == video_baseofs) 373 | { 374 | return; 375 | } 376 | video_baseofs = baseofs; 377 | 378 | glBindFramebuffer(GL_FRAMEBUFFER, fbo.frameBuffer[video_screenofs_fbo]); 379 | glViewport(0,0,fbo.width,fbo.height); 380 | } 381 | 382 | void VideoSetFrameBuffer(int crtc, int pel, video_fbo_t * vfbo) 383 | { 384 | int baseofs; 385 | GetAddressInfo(crtc, &baseofs, &vfbo->index); 386 | int ofs = crtc - baseofs; 387 | vfbo->xoffset = (ofs*8+pel)%(video_line_width*8); 388 | vfbo->yoffset = ofs/video_line_width; 389 | } 390 | 391 | float video_color_border[3]; 392 | void ColorBorder (int color) 393 | { 394 | char border[4]; 395 | *(unsigned int*)border = GetColor(color); 396 | video_color_border[0] = border[0]/256.f; 397 | video_color_border[1] = border[1]/256.f; 398 | video_color_border[2] = border[2]/256.f; 399 | } 400 | 401 | void VideoSync(void) 402 | { 403 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 404 | glViewport(viewportX,viewportY,viewportWidth,viewportHeight); 405 | glClearColor( 406 | video_color_border[0], 407 | video_color_border[1], 408 | video_color_border[2], 409 | 1); 410 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 411 | 412 | glViewport(viewportX,viewportY,viewportWidth,viewportHeight); 413 | 414 | float xoffset = (float)video_fbo.xoffset; 415 | float yoffset = (float)video_fbo.yoffset; 416 | 417 | float tsplit = video_split/(float)fbo.height; 418 | float vsplit = 1 - video_split/100.f; 419 | 420 | float twidth = 320.f/(float)fbo.width; 421 | float theight = 200.f/(float)fbo.height; 422 | 423 | float u0 = xoffset/(float)fbo.width; 424 | float u1 = u0 + twidth; 425 | float v0 = yoffset/(float)fbo.height; 426 | float v1 = v0 + tsplit; 427 | 428 | float texcoords[] = { 429 | u0, 1 - v0, 430 | u1, 1 - v0, 431 | u1, 1 - v1, 432 | u0, 1 - v1, 433 | }; 434 | 435 | float vertices[] = { 436 | -1, 1, 437 | 1, 1, 438 | 1, vsplit, 439 | -1, vsplit, 440 | }; 441 | 442 | UseFadeShader(video_fade, fbo.texture[video_fbo.index], vertices, texcoords); 443 | 444 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 445 | 446 | if (video_split < 200) 447 | { 448 | texcoords[0] = 0; 449 | texcoords[1] = 1; 450 | 451 | texcoords[2] = twidth; 452 | texcoords[3] = 1; 453 | 454 | texcoords[4] = twidth; 455 | texcoords[5] = 1-(theight-tsplit); 456 | 457 | texcoords[6] = 0; 458 | texcoords[7] = 1-(theight-tsplit); 459 | 460 | vertices[1] = vsplit; 461 | vertices[3] = vsplit; 462 | vertices[5] = -1; 463 | vertices[7] = -1; 464 | 465 | UseFadeShader(video_fade, fbo.texture[0], vertices, texcoords); 466 | 467 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 468 | } 469 | 470 | SDL_GL_SwapWindow( window ); 471 | 472 | glBindFramebuffer(GL_FRAMEBUFFER, fbo.frameBuffer[video_screenofs_fbo]); 473 | glViewport(0,0,fbo.width,fbo.height); 474 | } 475 | 476 | void CopyEGA(int wide, int height, int source, int dest) 477 | { 478 | video_fbo_t srcfbo; 479 | video_fbo_t dstfbo; 480 | VideoSetFrameBuffer(source, 0, &srcfbo); 481 | VideoSetFrameBuffer(dest, 0, &dstfbo); 482 | 483 | assert(srcfbo.index != dstfbo.index); 484 | 485 | glBindFramebuffer(GL_FRAMEBUFFER, fbo.frameBuffer[dstfbo.index]); 486 | 487 | int width = wide * 8; 488 | 489 | float w = width / (float)fbo.width; 490 | float h = height / (float)fbo.height; 491 | 492 | float u0 = srcfbo.xoffset / (float)fbo.width; 493 | float v0 = srcfbo.yoffset / (float)fbo.height; 494 | float u1 = u0+w; 495 | float v1 = v0+h; 496 | 497 | GLfloat texcoord[] = { 498 | u0, 1-v0, 499 | u1, 1-v0, 500 | u1, 1-v1, 501 | u0, 1-v1, 502 | }; 503 | 504 | float x0 = dstfbo.xoffset; 505 | float y0 = dstfbo.yoffset; 506 | float x1 = x0+width; 507 | float y1 = y0+height; 508 | 509 | GLfloat vertices[] = { 510 | x0, y0, 0, 511 | x1, y0, 0, 512 | x1, y1, 0, 513 | x0, y1, 0, 514 | }; 515 | 516 | UseTextureShader(matProj2D.m, vertices, false, fbo.texture[srcfbo.index], texcoord); 517 | 518 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 519 | 520 | glBindFramebuffer(GL_FRAMEBUFFER, fbo.frameBuffer[video_screenofs_fbo]); 521 | glViewport(0,0,fbo.width,fbo.height); 522 | } 523 | 524 | void EGASplitScreen (int linenum) // splits a 200 line screen 525 | { 526 | video_split = linenum; 527 | } 528 | 529 | void SetScreen(int crtc, int pel) 530 | { 531 | video_crtc = crtc; 532 | video_pel = pel; 533 | VideoSetFrameBuffer(crtc, pel, &video_fbo); 534 | VideoSync(); 535 | } 536 | 537 | void SetLineWidth (int width) 538 | { 539 | video_line_width = width; 540 | linewidth = width; 541 | } 542 | 543 | 544 | 545 | void FadeOut (void) 546 | { 547 | int i; 548 | 549 | for (i=3;i>=0;i--) 550 | { 551 | video_fade = i/3.f; 552 | WaitVBL(6); 553 | } 554 | } 555 | 556 | void FadeIn (void) 557 | { 558 | int i; 559 | 560 | for (i=0;i<4;i++) 561 | { 562 | video_fade = i/3.f; 563 | WaitVBL(6); 564 | } 565 | } 566 | 567 | void FadeUp (void) 568 | { 569 | int i; 570 | 571 | for (i=3;i<6;i++) 572 | { 573 | video_fade = (i-3)/2.f + 1.f; 574 | WaitVBL(6); 575 | } 576 | } 577 | 578 | void FadeDown (void) 579 | { 580 | int i; 581 | 582 | for (i=5;i>2;i--) 583 | { 584 | video_fade = (i-3)/2.f + 1.f; 585 | WaitVBL(6); 586 | } 587 | } 588 | 589 | 590 | 591 | 592 | void DrawPic (int x, int y, int picnum) 593 | { 594 | gltexture * shape = (gltexture*)grsegs[picnum+STARTPICS]; 595 | assert(shape); 596 | 597 | SetScreenOfs(); 598 | 599 | float w = (float)(shape->width); 600 | float h = (float)(shape->height); 601 | float tx = (float)(x*8 + video_screenofs_x); 602 | float ty = (float)(y + video_screenofs_y); 603 | 604 | GLfloat texcoord[] = { 605 | 0, 0, 606 | 1, 0, 607 | 1, 1, 608 | 0, 1, 609 | }; 610 | 611 | GLfloat vertices[] = { 612 | tx, ty, 0, 613 | w+tx, ty, 0, 614 | w+tx, h+ty, 0, 615 | tx, h+ty, 0, 616 | }; 617 | 618 | UseTextureShader(matProj2D.m, vertices, false, shape->texture, texcoord); 619 | 620 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 621 | } 622 | 623 | void DrawShape(int x,int y,unsigned scale, memptr shapeptr) 624 | { 625 | gltexture *shape = (gltexture*)shapeptr; 626 | 627 | SetScreenOfs(); 628 | 629 | float sx = (float)(shape->width * scale/64.f + video_screenofs_x); 630 | float sy = (float)(shape->height * scale/64.f + video_screenofs_y); 631 | float tx = (float)x - sx/2.f; 632 | float ty = (float)y - sy/2.f; 633 | 634 | GLfloat texcoord[] = { 635 | 0, 0, 636 | 1, 0, 637 | 1, 1, 638 | 0, 1, 639 | }; 640 | 641 | GLfloat vertices[] = { 642 | tx, ty, 0, 643 | sx+tx, ty, 0, 644 | sx+tx, sy+ty, 0, 645 | tx, sy+ty, 0, 646 | }; 647 | 648 | UseTextureShader(matProj2D.m, vertices, false, shape->texture, texcoord); 649 | 650 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 651 | } 652 | 653 | void DrawScaledShape(int sxl, int yl, int sxh, int yh, int shapexl, int shapexh, memptr shapeptr) 654 | { 655 | gltexture *shape = (gltexture*)shapeptr; 656 | 657 | SetScreenOfs(); 658 | 659 | float u0 = shapexl / (float)shape->width; 660 | float u1 = shapexh / (float)shape->width; 661 | 662 | GLfloat texcoord[] = { 663 | u0, 0, 664 | u1, 0, 665 | u1, 1, 666 | u0, 1, 667 | }; 668 | 669 | float x0 = (float)(sxl + video_screenofs_x); 670 | float y0 = (float)(yl + video_screenofs_y); 671 | float x1 = (float)(sxh + video_screenofs_x); 672 | float y1 = (float)(yh + video_screenofs_y); 673 | 674 | GLfloat vertices[] = { 675 | x0, y0, 0, 676 | x1, y0, 0, 677 | x1, y1, 0, 678 | x0, y1, 0, 679 | }; 680 | 681 | UseTextureShader(matProj2D.m, vertices, false, shape->texture, texcoord); 682 | 683 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 684 | } 685 | 686 | 687 | /* 688 | =========================================================================== 689 | 690 | PROPORTIONAL PRINTING ROUTINES 691 | 692 | =========================================================================== 693 | */ 694 | unsigned px,py; 695 | unsigned pxl,pxh,pyl,pyh; 696 | unsigned fontcolor = 15; 697 | unsigned pdrawmode = 0x18; 698 | 699 | 700 | void DrawPchar (int Char) 701 | { 702 | font_t *font = (font_t*)grsegs[STARTFONT]; 703 | int width = font->width[Char]; 704 | float total_width = (float)font->total_width; 705 | 706 | SetScreenOfs(); 707 | 708 | float u0 = font->location[Char] / total_width; 709 | float u1 = width / total_width + u0; 710 | GLfloat texcoord[] = { 711 | u0, 0, 712 | u1, 0, 713 | u1, 1, 714 | u0, 1, 715 | }; 716 | 717 | float x0 = (float)(px + video_screenofs_x); 718 | float y0 = (float)(py + video_screenofs_y); 719 | float x1 = x0 + width; 720 | float y1 = y0 + font->height; 721 | GLfloat vertices[] = { 722 | x0, y0, 0, 723 | x1, y0, 0, 724 | x1, y1, 0, 725 | x0, y1, 0, 726 | }; 727 | 728 | UseFontShader(matProj2D.m, vertices, false, fontcolor, font->texture, texcoord); 729 | 730 | if (pdrawmode == 0x18) 731 | { 732 | glEnable(GL_BLEND); 733 | glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR); 734 | } 735 | 736 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 737 | 738 | glDisable(GL_BLEND); 739 | 740 | px+=width; 741 | } 742 | 743 | 744 | void DrawChar (int x, int y, int charnum) 745 | { 746 | memptr * tiles = (memptr*)grsegs[STARTTILE8]; 747 | assert(charnum >= 0 && charnum < NUMTILE8); 748 | gltexture * shape = (gltexture*)tiles[charnum]; 749 | assert(shape); 750 | 751 | SetScreenOfs(); 752 | 753 | float w = (float)(shape->width); 754 | float h = (float)(shape->height); 755 | float tx = (float)(x*8 + video_screenofs_x); 756 | float ty = (float)(y + video_screenofs_y); 757 | 758 | GLfloat texcoord[] = { 759 | 0, 0, 760 | 1, 0, 761 | 1, 1, 762 | 0, 1, 763 | }; 764 | 765 | GLfloat vertices[] = { 766 | tx, ty, 0, 767 | w+tx, ty, 0, 768 | w+tx, h+ty, 0, 769 | tx, h+ty, 0, 770 | }; 771 | 772 | UseTextureShader(matProj2D.m, vertices, false, shape->texture, texcoord); 773 | 774 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 775 | } 776 | 777 | 778 | void XPlot (int x, int y, int color) 779 | { 780 | if (color == 0) 781 | { 782 | return; 783 | } 784 | 785 | SetScreenOfs(); 786 | 787 | float x0 = (float)(x + video_screenofs_x); 788 | float y0 = (float)(y + video_screenofs_y); 789 | float x1 = x0 + 1.f; 790 | float y1 = y0 + 1.f; 791 | 792 | GLfloat vertices[] = { 793 | x0, y0, 0, 794 | x1, y0, 0, 795 | x1, y1, 0, 796 | x0, y1, 0, 797 | }; 798 | 799 | UseColorShader(matProj2D.m, vertices, true, color); 800 | 801 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 802 | 803 | glDisable(GL_BLEND); 804 | } 805 | 806 | 807 | 808 | void Block (int x, int y, int color) 809 | { 810 | SetScreenOfs(); 811 | 812 | float x0 = (float)(x*8 + video_screenofs_x); 813 | float y0 = (float)(y*8 + video_screenofs_y); 814 | float x1 = x0 + 8.f; 815 | float y1 = y0 + 8.f; 816 | 817 | GLfloat vertices[] = { 818 | x0, y0, 0, 819 | x1, y0, 0, 820 | x1, y1, 0, 821 | x0, y1, 0, 822 | }; 823 | 824 | UseColorShader(matProj2D.m, vertices, false, color); 825 | 826 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 827 | } 828 | 829 | 830 | void DrawLine (int xl, int xh, int y,int color) 831 | { 832 | SetScreenOfs(); 833 | 834 | float x0 = (float)(xl + video_screenofs_x); 835 | float y0 = (float)(y + video_screenofs_y); 836 | float x1 = (float)(xh + 1 + video_screenofs_x); 837 | float y1 = y0 + 1.f; 838 | 839 | GLfloat vertices[] = { 840 | x0, y0, 0, 841 | x1, y0, 0, 842 | x1, y1, 0, 843 | x0, y1, 0, 844 | }; 845 | 846 | UseColorShader(matProj2D.m, vertices, false, color); 847 | 848 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 849 | } 850 | 851 | void Bar (int x, int y, int wide, int height, int color) 852 | { 853 | SetScreenOfs(); 854 | 855 | float x0 = (float)(x*8 + video_screenofs_x); 856 | float y0 = (float)(y + video_screenofs_y); 857 | float x1 = x0 + (float)(wide*8); 858 | float y1 = y0 + (float)height; 859 | 860 | GLfloat vertices[] = { 861 | x0, y0, 0, 862 | x1, y0, 0, 863 | x1, y1, 0, 864 | x0, y1, 0, 865 | }; 866 | 867 | UseColorShader(matProj2D.m, vertices, false, color); 868 | 869 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 870 | } 871 | 872 | void DrawRect (int x, int y, int width, int height, int color) 873 | { 874 | SetScreenOfs(); 875 | 876 | float x0 = (float)(x + video_screenofs_x); 877 | float y0 = (float)(y + video_screenofs_y); 878 | float x1 = x0 + (float)width; 879 | float y1 = y0 + (float)height; 880 | 881 | GLfloat vertices[] = { 882 | x0, y0, 0, 883 | x1, y0, 0, 884 | x1, y1, 0, 885 | x0, y1, 0, 886 | }; 887 | 888 | UseColorShader(matProj2D.m, vertices, false, color); 889 | 890 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 891 | } 892 | 893 | void DrawLineZ (int xl, int xh, int y, int zl, int zh,int color) 894 | { 895 | SetScreenOfs(); 896 | 897 | float x0 = (float)(xl + video_screenofs_x); 898 | float y0 = (float)(y + video_screenofs_y); 899 | float x1 = (float)(xh + 1 + video_screenofs_x); 900 | float y1 = y0 + 1.f; 901 | 902 | // calculated 1/50th of the reciprical of scale 903 | const float rscale = (1.4 * 320.f) * 0.02f; 904 | // inverse for opengl negative z 905 | float z0 = rscale / (float)zl - 1.f; 906 | float z1 = rscale / (float)zh - 1.f; 907 | 908 | GLfloat vertices[] = { 909 | x0, y0, z0, 910 | x1, y0, z1, 911 | x1, y1, z1, 912 | x0, y1, z0, 913 | }; 914 | 915 | UseColorShader(matProj2D.m, vertices, false, color); 916 | 917 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 918 | 919 | } 920 | 921 | float z_viewangle; 922 | 923 | void EnableZ(int x, int y, int width, int height, float viewx, float viewz, float viewangle) 924 | { 925 | SetScreenOfs(); 926 | glViewport(x, fbo.height - height - y, width, height); 927 | glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 928 | glEnable(GL_DEPTH_TEST); 929 | 930 | static float fov = 40.f*3.141593f/180.f; 931 | static float n = 1.f; 932 | static float f = 40.f; 933 | 934 | float aspect = width/(float)height; 935 | float Hfov = fov*0.5f; 936 | float Vfov = Hfov/aspect; 937 | Matrix4x4_SetProject(&matProj,Vfov,Vfov,Hfov,Hfov,n,f); 938 | 939 | z_viewangle = (viewangle-90) * 3.141593f / 180.f; 940 | 941 | Matrix4x4_FrontRotate(&matProj, 0, 1, 0, z_viewangle); 942 | Matrix4x4_FrontTranslate(&matProj, -viewx, 0, -viewz); 943 | } 944 | 945 | void DisableZ() 946 | { 947 | glDisable(GL_DEPTH_TEST); 948 | glViewport(0,0,fbo.width,fbo.height); 949 | } 950 | 951 | void DrawPlaneZ(float width, float length, float y, int color) 952 | { 953 | SetScreenOfs(); 954 | 955 | GLfloat vertices[] = { 956 | 0, y, 0, 957 | width, y, 0, 958 | width, y, length, 959 | 0, y, length, 960 | }; 961 | 962 | UseColorShader(matProj.m, vertices, false, color); 963 | 964 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 965 | } 966 | 967 | void DrawWallZ(float x0, float z0, float x1, float z1, int color) 968 | { 969 | SetScreenOfs(); 970 | 971 | GLfloat vertices[] = { 972 | x0, 0.5, z0, 973 | x1, 0.5, z1, 974 | x1,-0.5, z1, 975 | x0,-0.5, z0, 976 | }; 977 | 978 | UseColorShader(matProj.m, vertices, false, color); 979 | 980 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 981 | } 982 | 983 | void DrawShapeZ(float x, float z, memptr shapeseg) 984 | { 985 | gltexture * shape = (gltexture*)shapeseg; 986 | assert(shape); 987 | 988 | SetScreenOfs(); 989 | 990 | GLfloat texcoord[] = { 991 | 0, 0, 992 | 1, 0, 993 | 1, 1, 994 | 0, 1, 995 | }; 996 | 997 | float hw = 0.5f * shape->width / (float)shape->height; 998 | float rx = cosf(-z_viewangle) * hw; 999 | float rz = sinf(-z_viewangle) * hw; 1000 | float x0 = x - rx; 1001 | float z0 = z - rz; 1002 | float x1 = x + rx; 1003 | float z1 = z + rz; 1004 | 1005 | GLfloat vertices[] = { 1006 | x0, 0.5, z0, 1007 | x1, 0.5, z1, 1008 | x1,-0.5, z1, 1009 | x0,-0.5, z0, 1010 | }; 1011 | 1012 | UseTextureShader(matProj.m, vertices, false, shape->texture, texcoord); 1013 | 1014 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 1015 | } 1016 | -------------------------------------------------------------------------------- /HOVLOOP.C: -------------------------------------------------------------------------------- 1 | /* Hovertank 3-D Source Code 2 | * Copyright (C) 1993-2014 Flat Rock Software 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "HOVERDEF.H" 20 | #pragma hdrstop 21 | 22 | //========================================================================== 23 | 24 | // 25 | // map arrays 26 | // 27 | unsigned tilemap[MAPSIZE][MAPSIZE]; 28 | 29 | 30 | // 31 | // play stuff 32 | // 33 | 34 | int godmode,singlestep,leveldone,startlevel; 35 | 36 | int32_t score; 37 | 38 | timetype timestruct; 39 | 40 | objtype objlist[MAXOBJECTS],obon,*_new,*obj,*lastobj,*check; 41 | 42 | ControlStruct c; 43 | 44 | int numrefugees,totalrefugees,savedcount,killedcount; 45 | 46 | int bordertime; 47 | 48 | // 49 | // actor stuff 50 | // 51 | fixed warpx,warpy; // where to spawn warp gate 52 | fixed xmove,ymove; 53 | 54 | 55 | #define TIMEPOINTS 100 56 | #define REFUGEEPOINTS 10000 57 | 58 | //========================================================================== 59 | 60 | void DrawCockpit (void); 61 | void DrawScore (void); 62 | #if 0 63 | void FindFreeObj (void); 64 | void StartLevel (unsigned far *plane1); 65 | void DropTime (void); 66 | void ClipMove (void); 67 | void Thrust (void); 68 | void Reverse (void); 69 | void AfterBurn (void); 70 | void CalcBounds (void); 71 | void TransformObon (void); 72 | #endif 73 | 74 | void SpawnPlayer (fixed gx, fixed gy); 75 | #if 0 76 | void PlayerThink (void); 77 | void SpawnShot (fixed gx, fixed gy, int angle, classtype _class); 78 | void ShotThink (void); 79 | void ExplodeThink (void); 80 | #endif 81 | void SpawnRefugee (fixed gx, fixed gy, int sex); 82 | #if 0 83 | void KillRefugee (objtype *hit); 84 | void RefugeeThink (void); 85 | #endif 86 | void SpawnDrone (fixed gx, fixed gy); 87 | #if 0 88 | void DroneThink (void); 89 | #endif 90 | void SpawnTank (fixed gx, fixed gy); 91 | #if 0 92 | void TankThink (void); 93 | #endif 94 | void SpawnMutant (fixed gx, fixed gy); 95 | #if 0 96 | void MutantThink (void); 97 | void SpawnWarp (fixed gx, fixed gy); 98 | void WarpThink (void); 99 | 100 | void PlayLoop (void); 101 | #endif 102 | void PlayGame (void); 103 | 104 | //========================================================================== 105 | 106 | /* 107 | ================== 108 | = 109 | = DrawCockpit 110 | = 111 | ================== 112 | */ 113 | 114 | void DrawCockpit (void) 115 | { 116 | screenofs = 0; 117 | 118 | screencenterx=19; 119 | screencentery=7; 120 | 121 | #if 0 122 | EGAWRITEMODE(0); 123 | #endif 124 | DrawPic (0,0,DASHPIC); 125 | DrawScore (); 126 | } 127 | 128 | //========================================================================== 129 | 130 | /* 131 | =================== 132 | = 133 | = DrawScore 134 | = 135 | =================== 136 | */ 137 | 138 | void DrawScore (void) 139 | { 140 | int i; 141 | 142 | char str[512]; 143 | ltoa(score,str,10); 144 | sx = 22-strlen(str); 145 | sy = 7; 146 | screenofs = linewidth*2; 147 | for (i=0;i_class != nothing && _new<=lastobj) 176 | _new++; 177 | 178 | if (_new>lastobj) 179 | { 180 | lastobj++; 181 | if (lastobj>=&objlist[MAXOBJECTS]) 182 | Quit("Object list overflow!"); 183 | } 184 | 185 | memset (_new,0,sizeof(*_new)); 186 | 187 | _new->think = BadThink; 188 | } 189 | 190 | //========================================================================== 191 | 192 | /* 193 | ================== 194 | = 195 | = StartLevel 196 | = 197 | ================== 198 | */ 199 | 200 | void StartLevel (unsigned short *plane1) 201 | { 202 | unsigned x,y,tile,dir; 203 | int angle; 204 | fixed gx,gy; 205 | 206 | numrefugees = 0; 207 | 208 | for (y=0;yheight;y++) 209 | for (x=0;xwidth;x++) 210 | if ( (tile=*plane1++) > 0 ) 211 | { 212 | dir = tile>>8; // high byte gives starting dir 213 | tile &= 0xff; 214 | gx = x*TILEGLOBAL+TILEGLOBAL/2; 215 | gy = y*TILEGLOBAL+TILEGLOBAL/2; 216 | switch (tile) 217 | { 218 | case 1: 219 | SpawnRefugee (gx,gy,1); 220 | break; 221 | case 2: 222 | SpawnDrone (gx+TILEGLOBAL/2,gy+TILEGLOBAL/2); 223 | break; 224 | case 3: 225 | SpawnTank (gx+TILEGLOBAL/2,gy+TILEGLOBAL/2); 226 | break; 227 | case 4: 228 | SpawnMutant (gx+TILEGLOBAL/2,gy+TILEGLOBAL/2); 229 | break; 230 | case 5: 231 | SpawnShield (gx,gy); 232 | break; 233 | case 6: 234 | SpawnRefugee (gx,gy,0); 235 | break; 236 | case 0xfe: 237 | warpx =gx; // warp gate is spawned when all men are done 238 | warpy =gy; 239 | break; 240 | case 0xff: 241 | SpawnPlayer (gx,gy); 242 | angle = ANGLES/4-dir*ANGLES/4; 243 | if (angle<0) 244 | angle+= ANGLES; 245 | objlist[0].angle = angle; 246 | break; 247 | } 248 | } 249 | 250 | totalrefugees = numrefugees; 251 | } 252 | 253 | 254 | //========================================================================== 255 | 256 | /* 257 | ===================== 258 | = 259 | = DropTime 260 | = 261 | ===================== 262 | */ 263 | 264 | void DropTime (void) 265 | { 266 | static int32_t secondtics; 267 | int now; 268 | 269 | secondtics+= tics; 270 | if (secondtics<70) 271 | return; 272 | 273 | secondtics=0; // give the slow systems a little edge 274 | 275 | if (--timestruct.sec<0) 276 | { 277 | timestruct.sec = 59; 278 | if (--timestruct.min<0) 279 | leveldone = -1; 280 | else 281 | // 282 | // draw new minutes 283 | // 284 | DrawPic (6,48,DIGIT0PIC+timestruct.min); 285 | } 286 | // 287 | // draw new seconds 288 | // 289 | DrawPic (9,48,DIGIT0PIC+timestruct.sec/10); 290 | DrawPic (11,48,DIGIT0PIC+timestruct.sec%10); 291 | 292 | if (timestruct.min==0 && timestruct.sec<=20) 293 | PlaySound (LOWTIMESND); 294 | } 295 | 296 | //========================================================================== 297 | 298 | /* 299 | =================== 300 | = 301 | = ClipMove 302 | = 303 | = Only checks corners, so the object better be less than one tile wide! 304 | = 305 | =================== 306 | */ 307 | 308 | void ClipMove (void) 309 | { 310 | int xl,yl,xh,yh,tx,ty,nt1,nt2; 311 | fixed intersect,basex,basey,pointx,pointy; 312 | fixed inside,total; 313 | 314 | // 315 | // move player and check to see if any corners are in solid tiles 316 | // 317 | 318 | obon.x += xmove; 319 | obon.y += ymove; 320 | 321 | CalcBounds (); 322 | 323 | xl = obon.xl>>TILESHIFT; 324 | yl = obon.yl>>TILESHIFT; 325 | 326 | xh = obon.xh>>TILESHIFT; 327 | yh = obon.yh>>TILESHIFT; 328 | 329 | 330 | if (!tilemap[xl][yl] && !tilemap[xh][yl] 331 | && !tilemap[xh][yh] && !tilemap[xl][yh] ) 332 | return; // no corners in wall 333 | 334 | if (!SoundPlaying()) 335 | PlaySound (BUMPWALLSND); 336 | 337 | 338 | // 339 | // intersect the path with the tile edges to determine point of impact 340 | // 341 | 342 | // 343 | // clip to east / west walls 344 | // 345 | if (xmove>0) 346 | { 347 | inside = obon.xh & 0xffff; 348 | total = xmove; 349 | if (inside<=total) 350 | { 351 | if (total>1) 352 | intersect = ymove*inside/(total-1); 353 | else 354 | intersect = ymove; 355 | nt1 = (obon.yl-intersect)>>TILESHIFT; 356 | nt2 = (obon.yh-intersect)>>TILESHIFT; 357 | if ( ( tilemap[xh][nt1] && !tilemap[xh-1][nt1] ) 358 | || ( tilemap[xh][nt2] && !tilemap[xh-1][nt2] ) ) 359 | obon.x = (obon.xh & 0xffff0000) - (MINDIST + 1); 360 | } 361 | } 362 | else if (xmove<0) 363 | { 364 | inside = TILEGLOBAL- (obon.xl & 0xffff); 365 | total = -xmove; 366 | if (inside<=total) 367 | { 368 | if (total>1) 369 | intersect = ymove*inside/(total-1); 370 | else 371 | intersect = ymove; 372 | nt1 = (obon.yl-intersect)>>TILESHIFT; 373 | nt2 = (obon.yh-intersect)>>TILESHIFT; 374 | if ( ( tilemap[xl][nt1] && !tilemap[xl+1][nt1] ) 375 | || ( tilemap[xl][nt2] && !tilemap[xl+1][nt2] ) ) 376 | obon.x = (obon.xl & 0xffff0000) + TILEGLOBAL + (MINDIST + 1); 377 | } 378 | } 379 | 380 | // 381 | // clip to north / south walls 382 | // 383 | if (ymove>0) 384 | { 385 | inside = obon.yh & 0xffff; 386 | total = ymove; 387 | if (inside<=total) 388 | { 389 | if (total>1) 390 | intersect = xmove*inside/(total-1); 391 | else 392 | intersect = xmove; 393 | nt1 = (obon.xl-intersect)>>TILESHIFT; 394 | nt2 = (obon.xh-intersect)>>TILESHIFT; 395 | if ( ( tilemap[nt1][yh] && !tilemap[nt1][yh-1] ) 396 | || ( tilemap[nt2][yh] && !tilemap[nt2][yh-1] ) ) 397 | obon.y = (obon.yh & 0xffff0000) - (MINDIST + 1); 398 | } 399 | } 400 | else if (ymove<0) 401 | { 402 | inside = TILEGLOBAL- (obon.yl & 0xffff); 403 | total = -ymove; 404 | if (inside<=total) 405 | { 406 | if (total>1) 407 | intersect = xmove*inside/(total-1); 408 | else 409 | intersect = xmove; 410 | nt1 = (obon.xl-intersect)>>TILESHIFT; 411 | nt2 = (obon.xh-intersect)>>TILESHIFT; 412 | if ( ( tilemap[nt1][yl] && !tilemap[nt1][yl+1] ) 413 | || ( tilemap[nt2][yl] && !tilemap[nt2][yl+1] ) ) 414 | obon.y = (obon.yl & 0xffff0000) + TILEGLOBAL + (MINDIST + 1); 415 | } 416 | } 417 | 418 | } 419 | 420 | 421 | //========================================================================== 422 | 423 | /* 424 | ================== 425 | = 426 | = CalcBounds 427 | = 428 | ================== 429 | */ 430 | void CalcBounds (void) 431 | { 432 | // 433 | // calculate hit rect 434 | // 435 | obon.xl = obon.x - obon.size; 436 | obon.xh = obon.x + obon.size; 437 | obon.yl = obon.y - obon.size; 438 | obon.yh = obon.y + obon.size; 439 | } 440 | 441 | void CalcBoundsNew (void) 442 | { 443 | // 444 | // calculate hit rect 445 | // 446 | _new->xl = _new->x - _new->size; 447 | _new->xh = _new->x + _new->size; 448 | _new->yl = _new->y - _new->size; 449 | _new->yh = _new->y + _new->size; 450 | } 451 | 452 | //========================================================================== 453 | 454 | /* 455 | ================== 456 | = 457 | = TransformObon 458 | = 459 | = Calculates transformed position and updates radar 460 | = 461 | ================== 462 | */ 463 | 464 | void TransformObon (void) 465 | { 466 | int ratio,screenx,pixelscale; 467 | fixed gx,gy,gxt,gyt; 468 | int32_t absdx,absdy; 469 | 470 | // 471 | // translate point to view centered coordinates 472 | // 473 | gx = obon.x-viewx; 474 | gy = obon.y-viewy; 475 | 476 | // 477 | // calculate newx 478 | // 479 | gxt = FixedByFrac(gx,viewcos); 480 | gyt = FixedByFrac(gy,viewsin); 481 | obon.viewx = gxt-gyt; 482 | 483 | // 484 | // calculate newy 485 | // 486 | gxt = FixedByFrac(gx,viewsin); 487 | gyt = FixedByFrac(gy,viewcos); 488 | obon.viewy = gyt+gxt; 489 | 490 | // 491 | // update radar 492 | // 493 | if (obon.radarx) 494 | XPlot (obon.radarx,obon.radary,obon.radarcolor); 495 | 496 | absdx = abs(obon.viewx); 497 | absdy = abs(obon.viewy); 498 | 499 | if (absdx WARPSTEPS) 610 | time = WARPSTEPS; 611 | 612 | screenofs = screenloc[(screenpage+ time/CYCLETIME )%3]; 613 | 614 | SC_ScaleShape (CENTERX,64,255*FOCUS / (WARPSTEPS+FOCUS-time), 615 | scalesegs[WARP1PIC+ (time/CYCLETIME)%4] ); 616 | 617 | SetScreen (screenloc[(screenpage+ time/CYCLETIME )%3],0); 618 | } while (timehighscore) 654 | { 655 | PlaySound (HIGHSCORESND); 656 | ExpWin(18,11); 657 | py+=3; 658 | CPPrint ("New High Score!\n"); 659 | py+=5; 660 | CPPrint ("Score\n"); 661 | char str[512]; 662 | ltoa(score,str,10); 663 | CPPrint (str); 664 | PPrint ("\n\n"); 665 | CPPrint ("Old\n"); 666 | ltoa(highscore,str,10); 667 | CPPrint (str); 668 | PPrint ("\n"); 669 | py+=5; 670 | CPPrint ("Congratulations!\n"); 671 | CPPrint (""); 672 | Ack(); 673 | highscore = score; 674 | } 675 | 676 | } 677 | 678 | //========================================================================== 679 | 680 | /* 681 | ===================== 682 | = 683 | = Victory 684 | = 685 | ===================== 686 | */ 687 | 688 | void Victory (void) 689 | { 690 | FadeOut(); 691 | CacheDrawPic(ENDPIC); 692 | FadeIn(); 693 | DrawWindow (0,0,39,6); 694 | CPPrint ("Crowds of cheering people surround\n"); 695 | CPPrint ("your tank. Cargo lifts deliver your\n"); 696 | CPPrint ("impressive bounty. The crowd quiets\n"); 697 | CPPrint ("as a distinguished man steps forward.\n"); 698 | 699 | Ack(); 700 | EraseWindow(); 701 | 702 | CPPrint ("'Well done,' says the UFA President.\n"); 703 | CPPrint ("'You have saved many deserving people.'\n"); 704 | CPPrint ("\n"); 705 | CPPrint ("'Mr. Sledge? I said you've done well.'\n"); 706 | 707 | Ack(); 708 | EraseWindow(); 709 | 710 | CPPrint ("You ignore him and count the reward\n"); 711 | CPPrint ("again. He says, 'Too bad about those\n"); 712 | CPPrint ("ones you lost...'\n"); 713 | CPPrint ("'What? I dropped some bills?' you say.\n"); 714 | 715 | Ack(); 716 | 717 | DrawWindow (10,21,30,24); 718 | py+=3; 719 | CPPrint ("Game Over!"); 720 | 721 | Ack(); 722 | } 723 | 724 | //========================================================================== 725 | 726 | #include "HOVTEXT.C" 727 | 728 | /* 729 | ===================== 730 | = 731 | = BaseScreen 732 | = 733 | = Drop off hostages, get score, start new level 734 | = 735 | ===================== 736 | */ 737 | 738 | void BaseScreen (void) 739 | { 740 | int i; 741 | unsigned topofs; 742 | 743 | #ifdef TESTCASE 744 | level++; 745 | LoadLevel(); 746 | StopDrive(); 747 | return; 748 | #endif 749 | 750 | 751 | CachePic (STARTPICS+MISSIONPIC); 752 | // 753 | // cash screen 754 | // 755 | if (level!=startlevel) // send them straight into the first level 756 | { 757 | #ifndef PROFILE 758 | WarpEffect(); 759 | #endif 760 | 761 | CachePic (STARTPICS+UFAPIC); 762 | DrawPic (0,0,UFAPIC); 763 | if (killedcount>=savedcount) 764 | { 765 | CachePic (STARTPICS+MADUFAPIC); 766 | DrawPic (0,0,MADUFAPIC); 767 | MMSetPurge (&grsegs[STARTPICS+MADUFAPIC],3); 768 | } 769 | MMSetPurge (&grsegs[STARTPICS+UFAPIC],3); 770 | 771 | pxl= 176; 772 | pxh= 311; 773 | 774 | py=10; 775 | CPPrint ("UFA Headquarters\n"); 776 | py += 5; 777 | PPrint ("Saved:"); 778 | PPrintInt (savedcount); 779 | PPrint ("\nLost:"); 780 | PPrintInt (killedcount); 781 | topofs = screenofs; 782 | 783 | 784 | py += 5; 785 | PPrint ("\nSavior reward..."); 786 | screenofs = 0; // draw into the split screen 787 | 788 | // 789 | // points for saving refugees 790 | // 791 | for (i=1;i<=savedcount;i++) 792 | { 793 | DrawPic (1+2*(savedcount-i),6,EMPTYGUYPIC); 794 | score += REFUGEEPOINTS; 795 | PlaySound (GUYSCORESND); 796 | DrawScore (); 797 | #ifndef PROFILE 798 | if (NBKascii != 27) 799 | WaitVBL(30); 800 | #endif 801 | } 802 | 803 | screenofs = topofs; 804 | py += 5; 805 | PPrint ("\nTime bonus...\n"); 806 | screenofs = 0; // draw into the split screen 807 | 808 | // 809 | // points for time remaining 810 | // 811 | while (timestruct.sec || timestruct.min) 812 | { 813 | score += TIMEPOINTS; 814 | 815 | if (--timestruct.sec<0) 816 | { 817 | timestruct.sec = 59; 818 | if (--timestruct.min<0) 819 | { 820 | timestruct.sec = timestruct.min = 0; 821 | } 822 | DrawPic (6,48,DIGIT0PIC+timestruct.min); 823 | } 824 | DrawPic (9,48,DIGIT0PIC+timestruct.sec/10); 825 | DrawPic (11,48,DIGIT0PIC+timestruct.sec%10); 826 | 827 | if ( !(timestruct.sec%5) ) 828 | PlaySound (TIMESCORESND); 829 | DrawScore (); 830 | #ifndef PROFILE 831 | if (NBKascii != 27) 832 | WaitVBL(2); 833 | #endif 834 | } 835 | 836 | if (objlist[0].hitpoints<3) 837 | { 838 | screenofs = topofs; 839 | PPrint ("\nRepairing tank..."); 840 | screenofs = 0; // draw into the split screen 841 | // 842 | // heal tank 843 | // 844 | while (objlist[0].hitpoints<3 && score>10000) 845 | { 846 | score -= 10000; 847 | DrawScore (); 848 | HealPlayer (); 849 | #ifndef PROFILE 850 | if (NBKascii != 27) 851 | WaitVBL(60); 852 | #endif 853 | ColorBorder (0); 854 | bordertime = 0; 855 | } 856 | } 857 | 858 | screenofs = topofs; 859 | py = 110; 860 | if (level == NUMLEVELS) 861 | CPPrint ("Mission completed!"); 862 | else 863 | CPPrint ("GO TO NEXT SECTOR"); 864 | 865 | StopDrive (); 866 | 867 | #ifndef PROFILE 868 | Ack(); 869 | #endif 870 | 871 | if (level == NUMLEVELS) 872 | { 873 | Victory(); 874 | level++; 875 | return; 876 | } 877 | } 878 | 879 | MMSetPurge (&grsegs[STARTPICS+MISSIONPIC],3); 880 | MMSortMem(); // push all purgable stuff high for good cache 881 | FadeOut(); 882 | 883 | // 884 | // briefing screen 885 | // 886 | level++; 887 | LoadLevel(); 888 | 889 | StopDrive(); 890 | 891 | #if 0 892 | EGAWRITEMODE(0); 893 | _fmemset (MK_FP(0xa000,0),0,0xffff); 894 | #endif 895 | EGASplitScreen(200-STATUSLINES); 896 | SetLineWidth(SCREENWIDTH); 897 | DrawCockpit(); 898 | 899 | // 900 | // draw custom dash stuff 901 | // 902 | DrawPic (1,48,DIGIT0PIC+level/10); 903 | DrawPic (3,48,DIGIT0PIC+level%10); 904 | for (i=0;i_class) 958 | { 959 | obon=*obj; 960 | obon.think(); 961 | *obj=obon; 962 | } 963 | } 964 | 965 | DropTime(); 966 | 967 | if (keydown[0x57]) // DEBUG! 968 | { 969 | DamagePlayer(); 970 | ClearKeys(); 971 | } 972 | 973 | if (bordertime && (bordertime-=tics) <=0) 974 | { 975 | bordertime = 0; 976 | ColorBorder (0); 977 | } 978 | 979 | FinishView(); // base drawn by player think 980 | CheckKeys(); 981 | 982 | }while (!leveldone); 983 | 984 | } 985 | 986 | 987 | 988 | /* 989 | =================== 990 | = 991 | = PlayGame 992 | = 993 | =================== 994 | */ 995 | 996 | int levmin[20] = 997 | { 998 | 3,3,4,4,6, 999 | 5,5,5,5,5, 1000 | 7,7,7,7,7, 1001 | 9,9,9,9,9 1002 | }; 1003 | 1004 | void PlayGame (void) 1005 | { 1006 | int i,xl,yl,xh,yh; 1007 | char num[20]; 1008 | 1009 | level = startlevel = 0; 1010 | 1011 | if (bestlevel>1) 1012 | { 1013 | ExpWin(28,3); 1014 | py+=6; 1015 | PPrint(" Start at what level (1-"); 1016 | char str[80]; 1017 | itoa(bestlevel,str,10); 1018 | PPrint (str); 1019 | PPrint (")?"); 1020 | i = InputInt(); 1021 | if (i>=1 && i<=bestlevel) 1022 | { 1023 | level = startlevel = i-1; 1024 | } 1025 | } 1026 | 1027 | restart: 1028 | 1029 | resetgame = score = 0; 1030 | 1031 | do 1032 | { 1033 | 1034 | lastobj = &objlist[0]; 1035 | 1036 | #ifdef TESTCASE 1037 | level = 12; 1038 | #endif 1039 | 1040 | BaseScreen (); 1041 | if (level==21) 1042 | break; 1043 | 1044 | #ifdef TESTCASE 1045 | objlist[0].x = 3126021; 1046 | objlist[0].y = 522173; 1047 | objlist[0].angle = 170; 1048 | #endif 1049 | 1050 | savedcount = killedcount = 0; 1051 | 1052 | timestruct.min = levmin[level-1]; 1053 | timestruct.sec = 0; 1054 | if (level == 20) 1055 | timestruct.sec = 59; 1056 | 1057 | screenofs = 0; 1058 | DrawPic (6,48,DIGIT0PIC+timestruct.min); 1059 | DrawPic (9,48,DIGIT0PIC+timestruct.sec/10); 1060 | DrawPic (11,48,DIGIT0PIC+timestruct.sec%10); 1061 | 1062 | lasttimecount = timecount; 1063 | tics = 1; 1064 | leveldone = 0; 1065 | 1066 | if (level>bestlevel) 1067 | bestlevel = level; 1068 | 1069 | PlayLoop (); 1070 | 1071 | screenofs = 0; 1072 | for (obj=&objlist[1];obj_class && obj->radarx) 1074 | XPlot (obj->radarx,obj->radary,obj->radarcolor); 1075 | 1076 | if (bordertime) 1077 | { 1078 | bordertime = 0; 1079 | ColorBorder (0); 1080 | } 1081 | 1082 | } 1083 | while (leveldone>0); 1084 | 1085 | if (resetgame) 1086 | return; 1087 | 1088 | GameOver(); 1089 | 1090 | // 1091 | // continue 1092 | // 1093 | 1094 | if (level>2 && level<21) 1095 | { 1096 | DrawWindow (10,20,30,23); 1097 | py+=3; 1098 | CPPrint ("Continue game ?"); 1099 | ClearKeys(); 1100 | char ch = PGet(); 1101 | if (toupper(ch&0xff)=='Y') 1102 | { 1103 | level--; 1104 | startlevel = level; // don't show base screen 1105 | goto restart; 1106 | } 1107 | } 1108 | 1109 | } 1110 | 1111 | 1112 | 1113 | 1114 | --------------------------------------------------------------------------------