├── .gitignore ├── texture.pcx ├── Makefile ├── README ├── my_endian.h ├── main.c ├── my_endian.c ├── pcx.c └── scene.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | main 3 | -------------------------------------------------------------------------------- /texture.pcx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joshb/dynamiclightmaps/HEAD/texture.pcx -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-Wall -ansi -pedantic -D_GNU_SOURCE -I/usr/X11R6/include 3 | LDFLAGS=-pthread -L/usr/X11R6/lib -L/usr/local/lib -lm -lGL -lGLU -lglut 4 | OBJS=main.o my_endian.o pcx.o scene.o 5 | 6 | prtunnel: $(OBJS) 7 | $(CC) $(LDFLAGS) $(OBJS) -o main 8 | 9 | clean: 10 | rm -f main 11 | rm -f $(OBJS) 12 | 13 | main.o: main.c 14 | my_endian.o: my_endian.c 15 | pcx.o: pcx.c 16 | scene.o: scene.c 17 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is an OpenGL demo featuring dynamic lightmaps, 2 | created for an article at http://www.3ddrome.com/ 3 | It's been developed and tested on Slackware Linux. 4 | 5 | To build it, just run 'make' (you may have to edit the 6 | Makefile). This will create an executable called 'main' 7 | that you can then run - press the space bar to toggle 8 | lighting in the demo. 9 | 10 | The code is distributed under a BSD-style license. 11 | 12 | Josh Beam 13 | http://joshbeam.com/ 14 | -------------------------------------------------------------------------------- /my_endian.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2003 Josh A. Beam 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef __MY_ENDIAN_H__ 27 | #define __MY_ENDIAN_H__ 28 | 29 | #ifdef __GLIBC__ 30 | #include 31 | #else 32 | #include 33 | #endif 34 | 35 | #ifndef int8_t 36 | #define int8_t char 37 | #endif 38 | #ifndef uint8_t 39 | #define uint8_t unsigned char 40 | #endif 41 | #ifndef int16_t 42 | #define int16_t short 43 | #endif 44 | #ifndef uint16_t 45 | #define uint16_t unsigned short 46 | #endif 47 | #ifndef int32_t 48 | #define int32_t long 49 | #endif 50 | #ifndef uint32_t 51 | #define uint32_t unsigned long 52 | #endif 53 | 54 | #define native_to_le_float le_to_native_float 55 | #define native_to_le_int le_to_native_int 56 | #define native_to_le_uint le_to_native_uint 57 | #define native_to_le_short le_to_native_short 58 | #define native_to_le_ushort le_to_native_ushort 59 | 60 | float le_to_native_float(float f); 61 | int32_t le_to_native_int(int32_t i); 62 | uint32_t le_to_native_uint(uint32_t i); 63 | int16_t le_to_native_short(int16_t s); 64 | uint16_t le_to_native_ushort(uint16_t s); 65 | 66 | #endif /* __MY_ENDIAN_H__ */ 67 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2003 Josh A. Beam 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define WINWIDTH 400 32 | #define WINHEIGHT 300 33 | 34 | extern void scene_toggle_lighting(); 35 | extern void scene_render(); 36 | extern void scene_cycle(); 37 | 38 | static int window; 39 | 40 | void 41 | key_press(unsigned char key, int x, int y) 42 | { 43 | switch(key) { 44 | default: 45 | scene_toggle_lighting(); 46 | break; 47 | case 27: /* escape */ 48 | glutDestroyWindow(window); 49 | exit(0); 50 | break; 51 | } 52 | } 53 | 54 | int 55 | main(int argc, char *argv[]) 56 | { 57 | glutInit(&argc, argv); 58 | glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); 59 | glutInitWindowSize(WINWIDTH, WINHEIGHT); 60 | 61 | window = glutCreateWindow(argv[0]); 62 | #ifdef FULLSCREEN 63 | glutFullScreen(); 64 | #endif 65 | 66 | glutDisplayFunc(scene_render); 67 | glutIdleFunc(scene_cycle); 68 | glutKeyboardFunc(key_press); 69 | 70 | /* GL settings */ 71 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 72 | glClearDepth(1.0f); 73 | 74 | glDisable(GL_BLEND); 75 | glEnable(GL_DEPTH_TEST); 76 | glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 77 | 78 | glMatrixMode(GL_PROJECTION); 79 | glLoadIdentity(); 80 | gluPerspective(45.0f, (float)WINWIDTH / (float)WINHEIGHT, 0.1f, 200.0f); 81 | glMatrixMode(GL_MODELVIEW); 82 | 83 | glutMainLoop(); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /my_endian.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2003 Josh A. Beam 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include "my_endian.h" 28 | 29 | #ifndef UNKNOWN_ENDIAN 30 | #define UNKNOWN_ENDIAN 0 31 | #endif 32 | #ifndef LITTLE_ENDIAN 33 | #define LITTLE_ENDIAN 1 34 | #endif 35 | #ifndef BIG_ENDIAN 36 | #define BIG_ENDIAN 2 37 | #endif 38 | 39 | static uint32_t endian = UNKNOWN_ENDIAN; 40 | 41 | static uint32_t 42 | set_endian() 43 | { 44 | if(endian == UNKNOWN_ENDIAN) { 45 | unsigned char c[] = { 1, 0 }; 46 | unsigned short *p = (unsigned short *)c; 47 | 48 | if(*p == 1) { 49 | endian = LITTLE_ENDIAN; 50 | printf("Using little-endian byte ordering\n"); 51 | } else { 52 | endian = BIG_ENDIAN; 53 | printf("Using big-endian byte ordering\n"); 54 | } 55 | } 56 | 57 | return endian; 58 | } 59 | 60 | static float 61 | swap_float(float f) 62 | { 63 | float retval; 64 | uint8_t *p1 = (uint8_t *)&f; 65 | uint8_t *p2 = (uint8_t *)&retval; 66 | 67 | p2[0] = p1[3]; 68 | p2[1] = p1[2]; 69 | p2[2] = p1[1]; 70 | p2[3] = p1[0]; 71 | 72 | return retval; 73 | } 74 | 75 | static int32_t 76 | swap_int(int32_t i) 77 | { 78 | int32_t retval; 79 | uint8_t *p1 = (uint8_t *)&i; 80 | uint8_t *p2 = (uint8_t *)&retval; 81 | 82 | p2[0] = p1[3]; 83 | p2[1] = p1[2]; 84 | p2[2] = p1[1]; 85 | p2[3] = p1[0]; 86 | 87 | return retval; 88 | } 89 | 90 | static uint32_t 91 | swap_uint(uint32_t i) 92 | { 93 | uint32_t retval; 94 | uint8_t *p1 = (uint8_t *)&i; 95 | uint8_t *p2 = (uint8_t *)&retval; 96 | 97 | p2[0] = p1[3]; 98 | p2[1] = p1[2]; 99 | p2[2] = p1[1]; 100 | p2[3] = p1[0]; 101 | 102 | return retval; 103 | } 104 | 105 | static int16_t 106 | swap_short(int16_t s) 107 | { 108 | int16_t retval; 109 | uint8_t *p1 = (uint8_t *)&s; 110 | uint8_t *p2 = (uint8_t *)&retval; 111 | 112 | p2[0] = p1[1]; 113 | p2[1] = p1[0]; 114 | 115 | return retval; 116 | } 117 | 118 | static uint16_t 119 | swap_ushort(uint16_t s) 120 | { 121 | uint16_t retval; 122 | uint8_t *p1 = (uint8_t *)&s; 123 | uint8_t *p2 = (uint8_t *)&retval; 124 | 125 | p2[0] = p1[1]; 126 | p2[1] = p1[0]; 127 | 128 | return retval; 129 | } 130 | 131 | float 132 | le_to_native_float(float f) 133 | { 134 | if(set_endian() == BIG_ENDIAN) 135 | return swap_float(f); 136 | 137 | return f; 138 | } 139 | 140 | int32_t 141 | le_to_native_int(int32_t i) 142 | { 143 | if(set_endian() == BIG_ENDIAN) 144 | return swap_int(i); 145 | 146 | return i; 147 | } 148 | 149 | uint32_t 150 | le_to_native_uint(uint32_t i) 151 | { 152 | if(set_endian() == BIG_ENDIAN) 153 | return swap_uint(i); 154 | 155 | return i; 156 | } 157 | 158 | int16_t 159 | le_to_native_short(int16_t s) 160 | { 161 | if(set_endian() == BIG_ENDIAN) 162 | return swap_short(s); 163 | 164 | return s; 165 | } 166 | 167 | uint16_t 168 | le_to_native_ushort(uint16_t s) 169 | { 170 | if(set_endian() == BIG_ENDIAN) 171 | return swap_ushort(s); 172 | 173 | return s; 174 | } 175 | -------------------------------------------------------------------------------- /pcx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2003 Josh A. Beam 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include "my_endian.h" 29 | 30 | struct pcx_header { 31 | uint8_t manufacturer; 32 | uint8_t version; 33 | uint8_t encoding; 34 | uint8_t bitsperpixel; 35 | int16_t xmin; 36 | int16_t ymin; 37 | int16_t xmax; 38 | int16_t ymax; 39 | uint16_t horizdpi; 40 | uint16_t vertdpi; 41 | uint8_t palette[48]; 42 | uint8_t reserved; 43 | uint8_t colorplanes; 44 | uint16_t bytesperline; 45 | uint16_t palettetype; 46 | uint16_t hscrsize; 47 | uint16_t vscrsize; 48 | uint8_t filler[54]; 49 | }; 50 | 51 | static int 52 | read_scanline(FILE *fp, unsigned char *planes[], unsigned int num_planes, 53 | unsigned int bytesperline) 54 | { 55 | unsigned int i, j; 56 | unsigned int p, count; 57 | uint8_t byte; 58 | 59 | for(p = 0; p < num_planes; p++) { 60 | for(i = 0; i < bytesperline;) { 61 | if(fread(&byte, 1, 1, fp) != 1) 62 | return 0; 63 | 64 | if(byte >> 6 == 0x3) { 65 | count = byte & ~(0x3 << 6); 66 | if(count == 0) 67 | return 0; 68 | if(fread(&byte, 1, 1, fp) != 1) 69 | return 0; 70 | } else { 71 | count = 1; 72 | } 73 | 74 | for(j = 0; j < count; j++) 75 | planes[p][i++] = byte; 76 | 77 | if(i >= bytesperline) { 78 | p++; 79 | if(p >= num_planes) 80 | return 1; 81 | i = 0; 82 | } 83 | } 84 | } 85 | 86 | return 1; 87 | } 88 | 89 | static unsigned char * 90 | load_pcx_data_8(FILE *fp, int width, int height, 91 | unsigned int bytesperline) 92 | { 93 | int i, j; 94 | int max; 95 | unsigned char *data, *p_data; 96 | unsigned char *line, *planes[1]; 97 | unsigned int current_line = 0; 98 | uint8_t byte; 99 | unsigned char palette[256][3]; 100 | 101 | p_data = (unsigned char *)malloc(sizeof(unsigned char) * width * height); 102 | if(!p_data) 103 | return NULL; 104 | 105 | line = (unsigned char *)malloc(sizeof(unsigned char) * bytesperline); 106 | if(!line) { 107 | free(p_data); 108 | return NULL; 109 | } 110 | planes[0] = line; 111 | 112 | while(current_line < (unsigned int)height) { 113 | if(read_scanline(fp, planes, 1, bytesperline) == 0) { 114 | free(p_data); 115 | free(line); 116 | return NULL; 117 | } 118 | 119 | for(i = 0; i < width; i++) 120 | p_data[width * current_line + i] = planes[0][i]; 121 | 122 | current_line++; 123 | } 124 | 125 | /* read palette */ 126 | fseek(fp, -769, SEEK_END); 127 | fread(&byte, 1, 1, fp); 128 | if(byte != 12) { 129 | fprintf(stderr, "Error: This ain't a palette\n"); 130 | free(p_data); 131 | free(line); 132 | return NULL; 133 | } 134 | for(i = 0; i < 256; i++) 135 | fread(palette[i], 3, 1, fp); 136 | 137 | data = (unsigned char *)malloc(sizeof(unsigned char) * width * height * 3); 138 | if(!data) { 139 | free(p_data); 140 | free(line); 141 | return NULL; 142 | } 143 | 144 | max = width * height; 145 | j = 0; 146 | for(i = 0; i < max; i++) { 147 | data[j++] = palette[(p_data[i])][0]; 148 | data[j++] = palette[(p_data[i])][1]; 149 | data[j++] = palette[(p_data[i])][2]; 150 | } 151 | 152 | free(p_data); 153 | free(line); 154 | return data; 155 | } 156 | 157 | static unsigned char * 158 | load_pcx_data_24(FILE *fp, int width, int height, 159 | unsigned int bytesperline) 160 | { 161 | int i; 162 | unsigned char *data; 163 | unsigned char *line, *planes[3]; 164 | unsigned int current_line = 0; 165 | 166 | data = (unsigned char *)malloc(sizeof(unsigned char) * width * height * 3); 167 | if(!data) 168 | return NULL; 169 | 170 | line = (unsigned char *)malloc(sizeof(unsigned char) * bytesperline * 3); 171 | if(!line) { 172 | free(data); 173 | return NULL; 174 | } 175 | planes[0] = line; 176 | planes[1] = planes[0] + bytesperline; 177 | planes[2] = planes[1] + bytesperline; 178 | 179 | while(current_line < (unsigned int)height) { 180 | if(read_scanline(fp, planes, 3, bytesperline) == 0) { 181 | free(data); 182 | free(line); 183 | return NULL; 184 | } 185 | 186 | for(i = 0; i < width; i++) { 187 | data[width * current_line * 3 + i * 3 + 0] = planes[0][i]; 188 | data[width * current_line * 3 + i * 3 + 1] = planes[1][i]; 189 | data[width * current_line * 3 + i * 3 + 2] = planes[2][i]; 190 | } 191 | 192 | current_line++; 193 | } 194 | 195 | free(line); 196 | return data; 197 | } 198 | 199 | unsigned char * 200 | read_pcx(const char *filename, unsigned int *widthp, unsigned int *heightp) 201 | { 202 | FILE *fp; 203 | struct pcx_header header; 204 | unsigned char *data; 205 | int width, height; 206 | 207 | fp = fopen(filename, "rb"); 208 | if(!fp) { 209 | fprintf(stderr, "pcx Error: Couldn't open %s for reading\n", filename); 210 | return NULL; 211 | } 212 | 213 | fread(&header, sizeof(struct pcx_header), 1, fp); 214 | header.xmin = le_to_native_short(header.xmin); 215 | header.ymin = le_to_native_short(header.ymin); 216 | header.xmax = le_to_native_short(header.xmax); 217 | header.ymax = le_to_native_short(header.ymax); 218 | header.bytesperline = le_to_native_ushort(header.bytesperline); 219 | 220 | if(header.bitsperpixel != 8) { 221 | fprintf(stderr, "Error: %s has unsupported number of bits per pixel\n", filename); 222 | return NULL; 223 | } 224 | if(header.colorplanes != 1 && header.colorplanes != 3) { 225 | fprintf(stderr, "Error: %s has unsupported number of color planes\n", filename); 226 | return NULL; 227 | } 228 | 229 | width = header.xmax - header.xmin + 1; 230 | height = header.ymax - header.ymin + 1; 231 | 232 | if(width < 1 || height < 1) { 233 | fprintf(stderr, "Error: %s has bad dimensions (%dx%d)\n", filename, width, height); 234 | return NULL; 235 | } 236 | 237 | switch(header.colorplanes) { 238 | default: 239 | data = NULL; 240 | break; 241 | case 1: 242 | data = load_pcx_data_8(fp, width, height, header.bytesperline); 243 | break; 244 | case 3: 245 | data = load_pcx_data_24(fp, width, height, header.bytesperline); 246 | break; 247 | } 248 | 249 | fclose(fp); 250 | *widthp = width; 251 | *heightp = height; 252 | 253 | if(!data) 254 | fprintf(stderr, "Error: Unable to load %s\n", filename); 255 | 256 | return data; 257 | } 258 | -------------------------------------------------------------------------------- /scene.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2003 Josh A. Beam 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | * WHETHER IN CONTACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #define LIGHTMAP_SIZE 16 35 | 36 | extern unsigned char *read_pcx(const char *filename, unsigned int *widthp, unsigned int *heightp); 37 | 38 | struct surface { 39 | float vertices[4][3]; 40 | float matrix[9]; 41 | 42 | float s_dist, t_dist; 43 | }; 44 | 45 | static float 46 | dot_product(float v1[3], float v2[3]) 47 | { 48 | return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]); 49 | } 50 | 51 | static void 52 | normalize(float v[3]) 53 | { 54 | float f = 1.0f / sqrt(dot_product(v, v)); 55 | 56 | v[0] *= f; 57 | v[1] *= f; 58 | v[2] *= f; 59 | } 60 | 61 | static void 62 | cross_product(const float *v1, const float *v2, float *out) 63 | { 64 | out[0] = v1[1] * v2[2] - v1[2] * v2[1]; 65 | out[1] = v1[2] * v2[0] - v1[0] * v2[2]; 66 | out[2] = v1[0] * v2[1] - v1[1] * v2[0]; 67 | } 68 | 69 | static void 70 | multiply_vector_by_matrix(const float m[9], float v[3]) 71 | { 72 | float tmp[3]; 73 | 74 | tmp[0] = v[0] * m[0] + v[1] * m[3] + v[2] * m[6]; 75 | tmp[1] = v[0] * m[1] + v[1] * m[4] + v[2] * m[7]; 76 | tmp[2] = v[0] * m[2] + v[1] * m[5] + v[2] * m[8]; 77 | 78 | v[0] = tmp[0]; 79 | v[1] = tmp[1]; 80 | v[2] = tmp[2]; 81 | } 82 | 83 | static struct surface * 84 | new_surface(float vertices[4][3]) 85 | { 86 | int i, j; 87 | struct surface *surf; 88 | 89 | surf = malloc(sizeof(struct surface)); 90 | if(!surf) { 91 | fprintf(stderr, "Error: Couldn't allocate memory for surface\n"); 92 | return NULL; 93 | } 94 | 95 | for(i = 0; i < 4; i++) { 96 | for(j = 0; j < 3; j++) 97 | surf->vertices[i][j] = vertices[i][j]; 98 | } 99 | 100 | /* x axis of matrix points in world space direction of the s texture axis */ 101 | for(i = 0; i < 3; i++) 102 | surf->matrix[0 + i] = surf->vertices[3][i] - surf->vertices[0][i]; 103 | surf->s_dist = sqrt(dot_product(surf->matrix, surf->matrix)); 104 | normalize(surf->matrix); 105 | 106 | /* y axis of matrix points in world space direction of the t texture axis */ 107 | for(i = 0; i < 3; i++) 108 | surf->matrix[3 + i] = surf->vertices[1][i] - surf->vertices[0][i]; 109 | surf->t_dist = sqrt(dot_product(surf->matrix + 3, surf->matrix + 3)); 110 | normalize(surf->matrix + 3); 111 | 112 | /* z axis of matrix is the surface's normal */ 113 | cross_product(surf->matrix, surf->matrix + 3, surf->matrix + 6); 114 | 115 | return surf; 116 | } 117 | 118 | static float light_pos[3] = { 1.0f, 0.0f, 0.25f }; 119 | static float light_color[3] = { 1.0f, 1.0f, 1.0f }; 120 | 121 | static unsigned int 122 | generate_lightmap(struct surface *surf) 123 | { 124 | static unsigned char data[LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3]; 125 | static unsigned int lightmap_tex_num = 0; 126 | unsigned int i, j; 127 | float pos[3]; 128 | float step, s, t; 129 | 130 | if(lightmap_tex_num == 0) 131 | glGenTextures(1, &lightmap_tex_num); 132 | 133 | step = 1.0f / (float)LIGHTMAP_SIZE; 134 | 135 | s = t = 0.0f; 136 | for(i = 0; i < LIGHTMAP_SIZE; i++) { 137 | for(j = 0; j < LIGHTMAP_SIZE; j++) { 138 | float d; 139 | float tmp; 140 | 141 | pos[0] = surf->s_dist * s; 142 | pos[1] = surf->t_dist * t; 143 | pos[2] = 0.0f; 144 | multiply_vector_by_matrix(surf->matrix, pos); 145 | 146 | pos[0] += surf->vertices[0][0]; 147 | pos[1] += surf->vertices[0][1]; 148 | pos[2] += surf->vertices[0][2]; 149 | 150 | pos[0] -= light_pos[0]; 151 | pos[1] -= light_pos[1]; 152 | pos[2] -= light_pos[2]; 153 | 154 | d = dot_product(pos, pos) * 0.5f; 155 | if(d < 1.0f) 156 | d = 1.0f; 157 | tmp = 1.0f / d; 158 | 159 | data[i * LIGHTMAP_SIZE * 3 + j * 3 + 0] = (unsigned char)(255.0f * tmp * light_color[0]); 160 | data[i * LIGHTMAP_SIZE * 3 + j * 3 + 1] = (unsigned char)(255.0f * tmp * light_color[1]); 161 | data[i * LIGHTMAP_SIZE * 3 + j * 3 + 2] = (unsigned char)(255.0f * tmp * light_color[2]); 162 | 163 | s += step; 164 | } 165 | 166 | t += step; 167 | s = 0.0f; 168 | } 169 | 170 | glBindTexture(GL_TEXTURE_2D, lightmap_tex_num); 171 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 172 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 173 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 174 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 175 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 176 | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 177 | glTexImage2D(GL_TEXTURE_2D, 0, 3, LIGHTMAP_SIZE, LIGHTMAP_SIZE, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 178 | 179 | return lightmap_tex_num; 180 | } 181 | 182 | static int lighting = 1; 183 | 184 | void 185 | scene_toggle_lighting() 186 | { 187 | lighting = lighting ? 0 : 1; 188 | } 189 | 190 | static float cam_rot[3] = { 0.0f, 0.0f, 0.0f }; 191 | 192 | void 193 | scene_render() 194 | { 195 | static struct surface *surfaces[6] = {NULL,NULL,NULL,NULL,NULL,NULL}; 196 | static unsigned int surface_tex_num; 197 | int i; 198 | 199 | if(!surfaces[0]) { 200 | unsigned char *data; 201 | unsigned int width, height; 202 | float v[4][3]; 203 | 204 | glEnable(GL_TEXTURE_2D); 205 | 206 | /* load texture */ 207 | data = read_pcx("texture.pcx", &width, &height); 208 | glEnable(GL_TEXTURE_2D); 209 | glGenTextures(1, &surface_tex_num); 210 | glBindTexture(GL_TEXTURE_2D, surface_tex_num); 211 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 212 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 213 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 214 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 215 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 216 | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 217 | glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 218 | 219 | /* create surfaces */ 220 | v[0][0] = -1.0f; v[0][1] = 1.0f; v[0][2] = 3.0f; 221 | v[1][0] = -1.0f; v[1][1] = 1.0f; v[1][2] = 1.0f; 222 | v[2][0] = 1.0f; v[2][1] = 1.0f; v[2][2] = 1.0f; 223 | v[3][0] = 1.0f; v[3][1] = 1.0f; v[3][2] = 3.0f; 224 | surfaces[0] = new_surface(v); 225 | 226 | v[0][0] = 1.0f; v[0][1] = 1.0f; v[0][2] = -1.0f; 227 | v[1][0] = 1.0f; v[1][1] = -1.0f; v[1][2] = -1.0f; 228 | v[2][0] = -1.0f; v[2][1] = -1.0f; v[2][2] = -1.0f; 229 | v[3][0] = -1.0f; v[3][1] = 1.0f; v[3][2] = -1.0f; 230 | surfaces[1] = new_surface(v); 231 | 232 | v[0][0] = -1.0f; v[0][1] = 1.0f; v[0][2] = 1.0f; 233 | v[1][0] = -1.0f; v[1][1] = 1.0f; v[1][2] = -1.0f; 234 | v[2][0] = 1.0f; v[2][1] = 1.0f; v[2][2] = -1.0f; 235 | v[3][0] = 1.0f; v[3][1] = 1.0f; v[3][2] = 1.0f; 236 | surfaces[2] = new_surface(v); 237 | 238 | v[0][0] = 1.0f; v[0][1] = -1.0f; v[0][2] = 1.0f; 239 | v[1][0] = 1.0f; v[1][1] = -1.0f; v[1][2] = -1.0f; 240 | v[2][0] = -1.0f; v[2][1] = -1.0f; v[2][2] = -1.0f; 241 | v[3][0] = -1.0f; v[3][1] = -1.0f; v[3][2] = 1.0f; 242 | surfaces[3] = new_surface(v); 243 | 244 | v[0][0] = -1.0f; v[0][1] = 1.0f; v[0][2] = 1.0f; 245 | v[1][0] = -1.0f; v[1][1] = 1.0f; v[1][2] = -1.0f; 246 | v[2][0] = -1.0f; v[2][1] = -1.0f; v[2][2] = -1.0f; 247 | v[3][0] = -1.0f; v[3][1] = -1.0f; v[3][2] = 1.0f; 248 | surfaces[4] = new_surface(v); 249 | 250 | v[0][0] = 1.0f; v[0][1] = -1.0f; v[0][2] = 1.0f; 251 | v[1][0] = 1.0f; v[1][1] = -1.0f; v[1][2] = -1.0f; 252 | v[2][0] = 1.0f; v[2][1] = 1.0f; v[2][2] = -1.0f; 253 | v[3][0] = 1.0f; v[3][1] = 1.0f; v[3][2] = 1.0f; 254 | surfaces[5] = new_surface(v); 255 | } 256 | 257 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 258 | glLoadIdentity(); 259 | glTranslatef(0.0f, 0.0f, -5.0f); 260 | glRotatef(cam_rot[0], 1.0f, 0.0f, 0.0f); 261 | glRotatef(cam_rot[1], 0.0f, 1.0f, 0.0f); 262 | glRotatef(cam_rot[2], 0.0f, 0.0f, 1.0f); 263 | 264 | glActiveTextureARB(GL_TEXTURE0_ARB); 265 | glEnable(GL_TEXTURE_2D); 266 | glBindTexture(GL_TEXTURE_2D, surface_tex_num); 267 | glActiveTextureARB(GL_TEXTURE1_ARB); 268 | if(lighting) 269 | glEnable(GL_TEXTURE_2D); 270 | 271 | for(i = 0; i < 6; i++) { 272 | if(!surfaces[i]) 273 | break; 274 | 275 | if(lighting) 276 | glBindTexture(GL_TEXTURE_2D, generate_lightmap(surfaces[i])); 277 | glBegin(GL_QUADS); 278 | glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 0.0f); 279 | glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 0.0f); 280 | glVertex3fv(surfaces[i]->vertices[0]); 281 | glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 1.0f); 282 | glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 1.0f); 283 | glVertex3fv(surfaces[i]->vertices[1]); 284 | glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f, 1.0f); 285 | glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0f, 1.0f); 286 | glVertex3fv(surfaces[i]->vertices[2]); 287 | glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f, 0.0f); 288 | glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0f, 0.0f); 289 | glVertex3fv(surfaces[i]->vertices[3]); 290 | glEnd(); 291 | } 292 | 293 | /* render light */ 294 | glDisable(GL_TEXTURE_2D); 295 | glActiveTextureARB(GL_TEXTURE0_ARB); 296 | glDisable(GL_TEXTURE_2D); 297 | glColor3fv(light_color); 298 | glBegin(GL_QUADS); 299 | glVertex3f(light_pos[0] - 0.05f, light_pos[1] + 0.05f, light_pos[2] + 0.05f); 300 | glVertex3f(light_pos[0] - 0.05f, light_pos[1] - 0.05f, light_pos[2] + 0.05f); 301 | glVertex3f(light_pos[0] + 0.05f, light_pos[1] - 0.05f, light_pos[2] + 0.05f); 302 | glVertex3f(light_pos[0] + 0.05f, light_pos[1] + 0.05f, light_pos[2] + 0.05f); 303 | glEnd(); 304 | glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 305 | 306 | glFlush(); 307 | glutSwapBuffers(); 308 | } 309 | 310 | static unsigned int 311 | get_ticks() 312 | { 313 | struct timeval t; 314 | 315 | gettimeofday(&t, NULL); 316 | 317 | return (t.tv_sec * 1000) + (t.tv_usec / 1000); 318 | } 319 | 320 | void 321 | scene_cycle() 322 | { 323 | static float light_rot = 0.0f; 324 | static unsigned int prev_ticks = 0; 325 | unsigned int ticks; 326 | float time; 327 | 328 | if(!prev_ticks) 329 | prev_ticks = get_ticks(); 330 | 331 | ticks = get_ticks(); 332 | time = (float)(ticks - prev_ticks); 333 | prev_ticks = ticks; 334 | 335 | cam_rot[2] -= 0.01f * time; 336 | while(cam_rot[2] < 0.0f) 337 | cam_rot[2] += 360.0f; 338 | 339 | light_pos[0] = cos(light_rot) * 0.8f; 340 | light_pos[1] = sin(light_rot) * 0.8f; 341 | light_rot += 0.001f * time; 342 | 343 | scene_render(); 344 | } 345 | --------------------------------------------------------------------------------