deepstone
diff src/mingl.c @ 0:f04884489bad
dos3d initial import
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 21 Nov 2011 06:14:01 +0200 |
parents | |
children | 0e781cc43178 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/mingl.c Mon Nov 21 06:14:01 2011 +0200 1.3 @@ -0,0 +1,466 @@ 1.4 +/* 1.5 +256-color 3D graphics hack for real-mode DOS. 1.6 +Copyright (C) 2011 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 +#include <stdio.h> 1.22 +#include <stdlib.h> 1.23 +#include <string.h> 1.24 +#include <math.h> 1.25 +#include <assert.h> 1.26 +#include "mingl.h" 1.27 +#include "mglimpl.h" 1.28 + 1.29 +#define DOT(a, b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z) 1.30 + 1.31 +static void transform(vec4_t *res, vec4_t *v, float *mat); 1.32 +static void transform3(vec3_t *res, vec3_t *v, float *mat); 1.33 +static void vertex_proc(struct vertex *vert); 1.34 + 1.35 +static struct state st; 1.36 +static struct framebuffer fb; 1.37 + 1.38 +int mgl_init(int width, int height) 1.39 +{ 1.40 + int i; 1.41 + 1.42 + st.flags = 0; 1.43 + st.mmode = 0; 1.44 + 1.45 + mgl_front_face(MGL_CCW); 1.46 + mgl_cull_face(MGL_BACK); 1.47 + 1.48 + st.curv.cidx = 0; 1.49 + st.curv.energy = 1.0; 1.50 + st.curv.norm.x = st.curv.norm.y = st.curv.norm.z = 0.0; 1.51 + 1.52 + if(!(fb.pixels = malloc(width * height))) { 1.53 + return -1; 1.54 + } 1.55 + fb.width = width; 1.56 + fb.height = height; 1.57 + fb.zbuf = 0; 1.58 + 1.59 + if(mgl_rast_init(&st, &fb) == -1) { 1.60 + free(fb.pixels); 1.61 + return -1; 1.62 + } 1.63 + 1.64 + st.mtop[0] = st.mtop[1] = 0; 1.65 + 1.66 + mgl_matrix_mode(MGL_MODELVIEW); 1.67 + mgl_load_identity(); 1.68 + mgl_matrix_mode(MGL_PROJECTION); 1.69 + mgl_load_identity(); 1.70 + 1.71 + /* initial viewport in the size of the framebuffer */ 1.72 + st.vp[0] = st.vp[1] = 0; 1.73 + st.vp[2] = width; 1.74 + st.vp[3] = height; 1.75 + 1.76 + st.col_range = 256; 1.77 + for(i=0; i<MAX_LIGHTS; i++) { 1.78 + st.ldir[i].x = st.ldir[i].y = 0.0f; 1.79 + st.ldir[i].z = 1.0f; 1.80 + st.lint[i] = 0.0f; 1.81 + } 1.82 + 1.83 + return 0; 1.84 +} 1.85 + 1.86 +void mgl_free(void) 1.87 +{ 1.88 + mgl_rast_cleanup(); 1.89 + free(fb.pixels); 1.90 +} 1.91 + 1.92 +unsigned char *mgl_framebuffer(void) 1.93 +{ 1.94 + return fb.pixels; 1.95 +} 1.96 + 1.97 +void mgl_clear(int cidx) 1.98 +{ 1.99 + memset(fb.pixels, cidx, fb.width * fb.height); 1.100 +} 1.101 + 1.102 +void mgl_enable(unsigned int bit) 1.103 +{ 1.104 + st.flags |= bit; 1.105 +} 1.106 + 1.107 +void mgl_disable(unsigned int bit) 1.108 +{ 1.109 + st.flags &= ~bit; 1.110 +} 1.111 + 1.112 +void mgl_front_face(int ff) 1.113 +{ 1.114 + st.frontface = ff; 1.115 +} 1.116 + 1.117 +void mgl_cull_face(int cf) 1.118 +{ 1.119 + st.cullface = cf; 1.120 +} 1.121 + 1.122 +void mgl_color_range(int rng) 1.123 +{ 1.124 + st.col_range = rng; 1.125 +} 1.126 + 1.127 +void mgl_light_intensity(int ltidx, float intens) 1.128 +{ 1.129 + assert(ltidx >= 0 && ltidx < MAX_LIGHTS); 1.130 + st.lint[ltidx] = intens; 1.131 +} 1.132 + 1.133 +void mgl_light_direction(int ltidx, float x, float y, float z) 1.134 +{ 1.135 + vec3_t dir; 1.136 + float mag; 1.137 + assert(ltidx >= 0 && ltidx < MAX_LIGHTS); 1.138 + 1.139 + dir.x = x; 1.140 + dir.y = y; 1.141 + dir.z = z; 1.142 + transform3(&st.ldir[ltidx], &dir, st.matrix[MGL_MODELVIEW][st.mtop[MGL_MODELVIEW]]); 1.143 + 1.144 + mag = sqrt(DOT(st.ldir[ltidx], st.ldir[ltidx])); 1.145 + if(fabs(mag) < 1e-6) { 1.146 + mag = 1.0f; 1.147 + } 1.148 + st.ldir[ltidx].x /= mag; 1.149 + st.ldir[ltidx].y /= mag; 1.150 + st.ldir[ltidx].z /= mag; 1.151 +} 1.152 + 1.153 +void mgl_begin(int prim) 1.154 +{ 1.155 + st.prim = prim; 1.156 + st.vidx = 0; 1.157 + 1.158 + st.ord = st.frontface; 1.159 + if(st.cullface == MGL_FRONT) { 1.160 + st.ord = st.frontface == MGL_CCW ? MGL_CW : MGL_CCW; 1.161 + } 1.162 + 1.163 + /* select the correct rasterizer according to state */ 1.164 + mgl_rast_prepare(); 1.165 +} 1.166 + 1.167 +void mgl_end(void) 1.168 +{ 1.169 +} 1.170 + 1.171 +void mgl_vertex2f(float x, float y) 1.172 +{ 1.173 + mgl_vertex4f(x, y, 0.0f, 1.0f); 1.174 +} 1.175 + 1.176 +void mgl_vertex3f(float x, float y, float z) 1.177 +{ 1.178 + mgl_vertex4f(x, y, z, 1.0f); 1.179 +} 1.180 + 1.181 +void mgl_vertex4f(float x, float y, float z, float w) 1.182 +{ 1.183 + st.v[st.vidx].pos.x = x; 1.184 + st.v[st.vidx].pos.y = y; 1.185 + st.v[st.vidx].pos.z = z; 1.186 + st.v[st.vidx].pos.w = w; 1.187 + st.v[st.vidx].cidx = st.curv.cidx; 1.188 + st.v[st.vidx].energy = st.curv.energy; 1.189 + st.v[st.vidx].norm = st.curv.norm; 1.190 + st.v[st.vidx].tc = st.curv.tc; 1.191 + 1.192 + vertex_proc(st.v + st.vidx); 1.193 + 1.194 + if(++st.vidx >= st.prim) { 1.195 + switch(st.prim) { 1.196 + case MGL_POINTS: 1.197 + mgl_draw_point(st.v); 1.198 + break; 1.199 + case MGL_LINES: 1.200 + mgl_draw_line(st.v, st.v + 1); 1.201 + break; 1.202 + case MGL_TRIANGLES: 1.203 + case MGL_QUADS: 1.204 + mgl_draw_poly(st.v, st.prim); 1.205 + break; 1.206 + default: 1.207 + fprintf(stderr, "invalid primitive: %d\n", st.prim); 1.208 + abort(); 1.209 + } 1.210 + st.vidx = 0; 1.211 + } 1.212 +} 1.213 + 1.214 +void mgl_color1f(float energy) 1.215 +{ 1.216 + st.curv.energy = energy; 1.217 +} 1.218 + 1.219 +void mgl_index(int c) 1.220 +{ 1.221 + st.curv.cidx = c; 1.222 +} 1.223 + 1.224 +void mgl_normal(float x, float y, float z) 1.225 +{ 1.226 + st.curv.norm.x = x; 1.227 + st.curv.norm.y = y; 1.228 + st.curv.norm.z = z; 1.229 +} 1.230 + 1.231 +void mgl_texcoord2f(float x, float y) 1.232 +{ 1.233 + st.curv.tc.x = x; 1.234 + st.curv.tc.y = y; 1.235 +} 1.236 + 1.237 +static void transform(vec4_t *res, vec4_t *v, float *mat) 1.238 +{ 1.239 + res->x = mat[0] * v->x + mat[4] * v->y + mat[8] * v->z + mat[12] * v->w; 1.240 + res->y = mat[1] * v->x + mat[5] * v->y + mat[9] * v->z + mat[13] * v->w; 1.241 + res->z = mat[2] * v->x + mat[6] * v->y + mat[10] * v->z + mat[14] * v->w; 1.242 + res->w = mat[3] * v->x + mat[7] * v->y + mat[11] * v->z + mat[15] * v->w; 1.243 +} 1.244 + 1.245 +/* the matrix is 4x4 (16 floats), just ignoring anything out of the 3x3 */ 1.246 +static void transform3(vec3_t *res, vec3_t *v, float *mat) 1.247 +{ 1.248 + res->x = mat[0] * v->x + mat[4] * v->y + mat[8] * v->z; 1.249 + res->y = mat[1] * v->x + mat[5] * v->y + mat[9] * v->z; 1.250 + res->z = mat[2] * v->x + mat[6] * v->y + mat[10] * v->z; 1.251 +} 1.252 + 1.253 +static void vertex_proc(struct vertex *vert) 1.254 +{ 1.255 + vec4_t pview, pclip; 1.256 + 1.257 + float *mvmat = st.matrix[MGL_MODELVIEW][st.mtop[MGL_MODELVIEW]]; 1.258 + float *pmat = st.matrix[MGL_PROJECTION][st.mtop[MGL_PROJECTION]]; 1.259 + 1.260 + /* modelview transformation */ 1.261 + transform(&pview, &vert->pos, mvmat); 1.262 + 1.263 + if(st.flags & MGL_LIGHTING) { 1.264 + if((st.flags & MGL_SMOOTH) || st.vidx == 0) { 1.265 + int i; 1.266 + vec3_t norm; 1.267 + float irrad = 0.0f; 1.268 + 1.269 + transform3(&norm, &vert->norm, mvmat); 1.270 + 1.271 + for(i=0; i<MAX_LIGHTS; i++) { 1.272 + if(st.lint[i] > 1e-6f) { 1.273 + float ndotl = DOT(norm, st.ldir[i]); 1.274 + if(ndotl < 0.0) { 1.275 + ndotl = 0.0; 1.276 + } 1.277 + irrad += ndotl * st.lint[i]; 1.278 + } 1.279 + } 1.280 + vert->energy = irrad; 1.281 + } else { 1.282 + vert->energy = st.v[0].energy; 1.283 + } 1.284 + } 1.285 + 1.286 + transform(&pclip, &pview, pmat); 1.287 + /* TODO clipping in homogenous clip space */ 1.288 + 1.289 + if(pclip.w < 1e-6 && pclip.w > -1e-6) { 1.290 + vert->pos.x = vert->pos.y = vert->pos.z = vert->pos.w = 0.0f; 1.291 + return; 1.292 + } 1.293 + 1.294 + /* perspective division */ 1.295 + vert->pos.x = pclip.x / pclip.w; 1.296 + vert->pos.y = pclip.y / pclip.w; 1.297 + vert->pos.z = pclip.z / pclip.w; 1.298 + vert->pos.w = pclip.w; 1.299 + 1.300 + /* viewport transformation */ 1.301 + vert->pos.x = st.vp[0] + st.vp[2] * (vert->pos.x * 0.5 + 0.5); 1.302 + vert->pos.y = st.vp[1] + st.vp[3] * (-vert->pos.y * 0.5 + 0.5); 1.303 +} 1.304 + 1.305 +void mgl_viewport(int x, int y, int width, int height) 1.306 +{ 1.307 + st.vp[0] = x; 1.308 + st.vp[1] = y; 1.309 + st.vp[2] = width; 1.310 + st.vp[3] = height; 1.311 +} 1.312 + 1.313 +void mgl_matrix_mode(int mmode) 1.314 +{ 1.315 + st.mmode = mmode; 1.316 +} 1.317 + 1.318 +void mgl_push_matrix(void) 1.319 +{ 1.320 + float *topmat; 1.321 + if(st.mtop[st.mmode] >= MATRIX_STACK_SIZE - 1) { 1.322 + fprintf(stderr, "mgl_push_matrix: stack overflow\n"); 1.323 + abort(); 1.324 + } 1.325 + 1.326 + topmat = st.matrix[st.mmode][st.mtop[st.mmode]]; 1.327 + memcpy(topmat + 16, topmat, 16 * sizeof *topmat); 1.328 + st.mmode++; 1.329 +} 1.330 + 1.331 +void mgl_pop_matrix(void) 1.332 +{ 1.333 + if(st.mtop[st.mmode] <= 0) { 1.334 + fprintf(stderr, "mgl_pop_matrix: stack underflow\n"); 1.335 + abort(); 1.336 + } 1.337 + st.mtop[st.mmode]--; 1.338 +} 1.339 + 1.340 +void mgl_load_matrix(float *mat) 1.341 +{ 1.342 + float *dest = st.matrix[st.mmode][st.mtop[st.mmode]]; 1.343 + memcpy(dest, mat, 16 * sizeof *dest); 1.344 +} 1.345 + 1.346 +#define M(i,j) (((j) << 2) + (i)) 1.347 +void mgl_mult_matrix(float *m2) 1.348 +{ 1.349 + int i, j; 1.350 + float m1[16]; 1.351 + float *dest = st.matrix[st.mmode][st.mtop[st.mmode]]; 1.352 + 1.353 + memcpy(m1, dest, sizeof m1); 1.354 + 1.355 + for(i=0; i<4; i++) { 1.356 + for(j=0; j<4; j++) { 1.357 + dest[M(i,j)] = m1[M(0,j)] * m2[M(i,0)] + 1.358 + m1[M(1,j)] * m2[M(i,1)] + 1.359 + m1[M(2,j)] * m2[M(i,2)] + 1.360 + m1[M(3,j)] * m2[M(i,3)]; 1.361 + } 1.362 + } 1.363 +} 1.364 + 1.365 +void mgl_load_identity(void) 1.366 +{ 1.367 + static float id[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; 1.368 + mgl_load_matrix((float*)id); 1.369 +} 1.370 + 1.371 +void mgl_translate(float x, float y, float z) 1.372 +{ 1.373 + float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; 1.374 + xform[12] = x; 1.375 + xform[13] = y; 1.376 + xform[14] = z; 1.377 + mgl_mult_matrix(xform); 1.378 +} 1.379 + 1.380 +void mgl_rotate(float deg, float x, float y, float z) 1.381 +{ 1.382 + float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; 1.383 + 1.384 + float angle = M_PI * deg / 180.0f; 1.385 + float sina = sin(angle); 1.386 + float cosa = cos(angle); 1.387 + float one_minus_cosa = 1.0f - cosa; 1.388 + float nxsq = x * x; 1.389 + float nysq = y * y; 1.390 + float nzsq = z * z; 1.391 + 1.392 + xform[0] = nxsq + (1.0f - nxsq) * cosa; 1.393 + xform[4] = x * y * one_minus_cosa - z * sina; 1.394 + xform[8] = x * z * one_minus_cosa + y * sina; 1.395 + xform[1] = x * y * one_minus_cosa + z * sina; 1.396 + xform[5] = nysq + (1.0 - nysq) * cosa; 1.397 + xform[9] = y * z * one_minus_cosa - x * sina; 1.398 + xform[2] = x * z * one_minus_cosa - y * sina; 1.399 + xform[6] = y * z * one_minus_cosa + x * sina; 1.400 + xform[10] = nzsq + (1.0 - nzsq) * cosa; 1.401 + 1.402 + mgl_mult_matrix(xform); 1.403 +} 1.404 + 1.405 +void mgl_scale(float x, float y, float z) 1.406 +{ 1.407 + float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; 1.408 + xform[0] = x; 1.409 + xform[5] = y; 1.410 + xform[10] = z; 1.411 + mgl_mult_matrix(xform); 1.412 +} 1.413 + 1.414 +void gl_ortho(float left, float right, float bottom, float top, float nr, float fr) 1.415 +{ 1.416 + float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; 1.417 + 1.418 + float dx = right - left; 1.419 + float dy = top - bottom; 1.420 + float dz = fr - nr; 1.421 + 1.422 + float tx = -(right + left) / dx; 1.423 + float ty = -(top + bottom) / dy; 1.424 + float tz = -(fr + nr) / dz; 1.425 + 1.426 + float sx = 2.0 / dx; 1.427 + float sy = 2.0 / dy; 1.428 + float sz = -2.0 / dz; 1.429 + 1.430 + xform[0] = sx; 1.431 + xform[5] = sy; 1.432 + xform[10] = sz; 1.433 + xform[12] = tx; 1.434 + xform[13] = ty; 1.435 + xform[14] = tz; 1.436 + 1.437 + mgl_mult_matrix(xform); 1.438 +} 1.439 + 1.440 +void mgl_frustum(float left, float right, float bottom, float top, float nr, float fr) 1.441 +{ 1.442 + float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; 1.443 + 1.444 + float dx = right - left; 1.445 + float dy = top - bottom; 1.446 + float dz = fr - nr; 1.447 + 1.448 + float a = (right + left) / dx; 1.449 + float b = (top + bottom) / dy; 1.450 + float c = -(fr + nr) / dz; 1.451 + float d = -2.0 * fr * nr / dz; 1.452 + 1.453 + xform[0] = 2.0 * nr / dx; 1.454 + xform[5] = 2.0 * nr / dy; 1.455 + xform[8] = a; 1.456 + xform[9] = b; 1.457 + xform[10] = c; 1.458 + xform[11] = -1.0f; 1.459 + xform[14] = d; 1.460 + 1.461 + mgl_mult_matrix(xform); 1.462 +} 1.463 + 1.464 +void mgl_perspective(float vfov, float aspect, float nr, float fr) 1.465 +{ 1.466 + float vfov_rad = M_PI * vfov / 180.0; 1.467 + float x = nr * tan(vfov_rad / 2.0); 1.468 + mgl_frustum(-aspect * x, aspect * x, -x, x, nr, fr); 1.469 +}