📄 skyfly.c
字号:
/*
* skyfly.c $Revision: 1.5 $
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <GL/glut.h>
#include <math.h>
#include "skyfly.h"
#if !defined(GL_VERSION_1_1)
#if defined(GL_EXT_texture_object)
#define glBindTexture(A,B) glBindTextureEXT(A,B)
#define glGenTextures(A,B) glGenTexturesEXT(A,B)
#define glDeleteTextures(A,B) glDeleteTexturesEXT(A,B)
#else
#define glBindTexture(A,B)
#define glGenTextures(A,B)
#define glDeleteTextures(A,B)
#endif
#if defined(GL_EXT_texture)
#define GL_RGB5 GL_RGB5_EXT
#else
#define GL_RGB5 GL_RGB
#endif
#endif
#define ERR_WARNING 0x1
#define ERR_FATAL 0x2
#define ERR_SYSERR 0x4
#define AMALLOC(a, type, num, func) { \
if((int)(a = (type*)malloc(sizeof(type)*(num))) <= 0) \
err_msg(ERR_FATAL, func, "amalloc failed"); \
}
float ScaleZ = 2.3; /* Terrain height scale factor */
int CellDim = 4; /* Terrain cell is CellDim X Celldim quads */
int NumCells = 36; /* Terrain grid is NumCells X NumCells cells */
int GridDim; /* Terrain grid is GridDim X GridDim quads */
float XYScale; /* Conversion from world-space to grid index */
float CellSize; /* World-space size of cell */
int Init_pos; /* if true, set initial position and kbd mode */
float Init_x, Init_y, Init_z, Init_azimuth;
int rgbmode = GL_TRUE;
/* Color index ramp info */
int sky_base, terr_base;
int plane_colors[3];
/*
* Data that changes from frame to frame needs to be double-buffered because
* two processes may be working on two different frames at the same time.
*/
typedef struct buffered_data_struct {
/* objects */
perfobj_t paper_plane_pos_obj[NUM_PLANES];
perfobj_t viewer_pos_obj;
/* flags */
unsigned int paper_plane_pos_flags[2];
unsigned int viewer_pos_flags[2];
/* data */
float paper_plane_position[NUM_PLANES][6];
float viewer_position[4];
} buffered_data;
/*
* This is the per-pipe data structure which holds pipe id, semaphores,
* and variable data buffers. Both gfxpipe and buffer structures live in
* shared memory so the sim can communicate with its forked children.
*/
typedef struct gfxpipe_data_struct {
int gfxpipenum;
buffered_data **buffers;
} gfxpipe_data;
static gfxpipe_data *gfxpipe; /* A processes' gfxpipe struct */
static gfxpipe_data *gfxpipes[1]; /* Maximum of 1 graphics pipe */
static int num_pipes;
float fog_params[4]; /* Fog and clear color */
static float fog_density = 0.025*2;
float far_cull = 31.; /* Far clip distance from eye */
int mipmap = 0;
static int texmode = GL_NEAREST;
static int threecomp = 1;
int dither = GL_TRUE, fog = GL_TRUE;
int Wxsize = 320, Wysize = 240; /* Default to 320x240 window */
/*
* All non-variable data like geometry is stored in shared memory. This way
* forked processes avoid duplicating data unnecessarily.
*/
shared_data *SharedData;
/* //////////////////////////////////////////////////////////////////////// */
void sim_proc(void);
void sim_cyclops(void);
void sim_dualchannel(void);
void sim_singlechannel(void);
void cull_proc(void);
void draw_proc(void);
void sim_exit(void);
void init_misc(void);
void init_shmem(void);
void init_terrain(void);
void init_clouds(void);
void init_paper_planes(void);
void init_positions(void);
void init_gfxpipes(void);
void init_gl(int gfxpipenum);
void err_msg(int type, char* func, char* error);
void fly(perfobj_t *viewer_pos);
void fly_paper_planes(perfobj_t *paper_plane_pos);
float terrain_height(void);
void init_skyfly(void)
{
init_shmem();
init_gfxpipes();
init_clouds();
init_terrain();
init_paper_planes();
init_positions();
gfxpipe = gfxpipes[0];
init_gl(gfxpipe->gfxpipenum);
}
/*
* This is a single-channel version of the dual-channel simulation
* described above.
*/
void sim_singlechannel(void)
{
buffered_data **buffered = gfxpipes[0]->buffers;
fly(&(buffered[0]->viewer_pos_obj));
fly_paper_planes(buffered[0]->paper_plane_pos_obj);
}
/*-------------------------------------- Cull ------------------------------*/
/*
* The cull and draw processes operate in a classic producer/consumer,
* write/read configuration using a ring buffer. The ring consists of pointers
* to perfobj's instead of actual geometric data. This is important because
* you want to minimize the amount of data 'shared' between two processes that
* run on different processors in order to reduce cache invalidations.
* enter_in_ring and get_from_ring spin on ring full and ring empty
* conditions respectively.
* Since cull/draw are shared group processes(sproc), the ring buffer is
* in the virtual address space of both processes and shared memory is not
* necessary.
*/
#define RING_SIZE 1000 /* Size of ring */
typedef struct render_ring_struct {
volatile unsigned int head, tail;
perfobj_t **ring;
} render_ring;
render_ring ringbuffer;
void enter_in_ring(perfobj_t *perfobj);
perfobj_t* get_from_ring(void);
void cull_proc(void)
{
static struct cull {
perfobj_t **cells;
perfobj_t viewer_pos_obj[2];
unsigned int viewer_pos_flags[4];
float viewer_position[2][4];
float fovx, side, farr, epsilon, plane_epsilon;
} cull;
static int init = 0;
if (!init) {
int x, y;
cull.fovx = FOV *(float) Wxsize /(float) Wysize;
cull.side = far_cull / cosf(cull.fovx / 2.);
cull.farr = 2.* cull.side * sinf(cull.fovx / 2.);
cull.epsilon = sqrtf(2.) * CellSize / 2.;
cull.plane_epsilon = .5;
cull.cells = (perfobj_t **) malloc(NumCells * NumCells * sizeof(perfobj_t *));
for (x = 0; x < NumCells; x++)
for (y = 0; y < NumCells; y++)
cull.cells[x * NumCells + y] =
&(SharedData->terrain_cells[x * NumCells + y]);
ringbuffer.ring = malloc(RING_SIZE * sizeof(perfobj_t *));
ringbuffer.head = ringbuffer.tail = 0;
cull.viewer_pos_obj[0].flags = cull.viewer_pos_flags;
cull.viewer_pos_obj[0].vdata = cull.viewer_position[0];
cull.viewer_pos_obj[1].flags = cull.viewer_pos_flags;
cull.viewer_pos_obj[1].vdata = cull.viewer_position[1];
*(cull.viewer_pos_flags) = PD_VIEWER_POS;
*(cull.viewer_pos_flags + 1) = PD_END;
init = 1;
}
{
float *viewer;
float vX, vY, vazimuth, px, py;
float left_area, right_area;
float left_dx, left_dy, right_dx, right_dy;
float ax, ay, bx, by, cx, cy;
float minx, maxx, miny, maxy;
int i, buffer = 0;
int x, y, x0, y0, x1, y1;
perfobj_t *viewer_pos, *paper_plane_pos;
buffered_data *buffered;
perfobj_t *terrain_texture = &(SharedData->terrain_texture_obj);
perfobj_t *paper_plane = &(SharedData->paper_plane_obj);
perfobj_t *paper_plane_start = &(SharedData->paper_plane_start_obj);
perfobj_t *paper_plane_end = &(SharedData->paper_plane_end_obj);
perfobj_t *clouds_texture = &(SharedData->clouds_texture_obj);
perfobj_t *clouds = &(SharedData->clouds_obj);
buffered = gfxpipe->buffers[buffer];
viewer_pos = &(buffered->viewer_pos_obj);
paper_plane_pos = buffered->paper_plane_pos_obj;
vX = *((float *) viewer_pos->vdata + 0);
vY = *((float *) viewer_pos->vdata + 1);
vazimuth = *((float *) viewer_pos->vdata + 3);
viewer = cull.viewer_position[buffer];
viewer[0] = vX;
viewer[1] = vY;
viewer[2] = *((float *) viewer_pos->vdata + 2);
viewer[3] = vazimuth;
/*
* Begin cull to viewing frustrum
*/
ax = (vX - sinf(-vazimuth + cull.fovx *.5) * cull.side);
ay = (vY + cosf(-vazimuth + cull.fovx *.5) * cull.side);
bx = vX;
by = vY;
cx = (vX + sinf(vazimuth + cull.fovx *.5) * cull.side);
cy = (vY + cosf(vazimuth + cull.fovx *.5) * cull.side);
minx = MIN(MIN(ax, bx), cx);
miny = MIN(MIN(ay, by), cy);
maxx = MAX(MAX(ax, bx), cx);
maxy = MAX(MAX(ay, by), cy);
x0 = MAX((int) (minx / CellSize), 0);
x1 = MIN((int) (maxx / CellSize) + 1, NumCells);
y0 = MAX((int) (miny / CellSize), 0);
y1 = MIN((int) (maxy / CellSize) + 1, NumCells);
left_dx = ax - bx;
left_dy = ay - by;
right_dx = cx - bx;
right_dy = cy - by;
enter_in_ring(&cull.viewer_pos_obj[buffer]);
if (viewer[2]<SKY_HIGH) {
/* draw clouds first */
enter_in_ring(clouds_texture);
enter_in_ring(clouds);
}
enter_in_ring(terrain_texture);
/*
* Add visible cells to ring buffer
*/
for (x = x0; x < x1; x++) {
for (y = y0; y < y1; y++) {
float cntrx =(x +.5) * CellSize;
float cntry =(y +.5) * CellSize;
left_area = left_dx * (cntry - by) - left_dy * (cntrx - bx);
right_area = right_dx * (cntry - by) - right_dy * (cntrx - bx);
if ((left_area < cull.epsilon * cull.side && right_area > -cull.epsilon * cull.side)) {
enter_in_ring(cull.cells[x * NumCells + y]);
}
}
}
enter_in_ring(paper_plane_start);
/*
* Add visible planes to ring buffer
*/
for (i = 0; i < NUM_PLANES; i++) {
px = *((float *) paper_plane_pos[i].vdata + 0);
py = *((float *) paper_plane_pos[i].vdata + 1);
left_area = left_dx * (py - by) - left_dy * (px - bx);
right_area = right_dx * (py - by) - right_dy * (px - bx);
if (left_area < cull.plane_epsilon * cull.side && right_area > -cull.plane_epsilon * cull.side) {
enter_in_ring(&paper_plane_pos[i]);
enter_in_ring(paper_plane);
}
}
enter_in_ring(paper_plane_end);
if (viewer[2]>SKY_HIGH) {
/* draw clouds after everything else */
enter_in_ring(clouds_texture);
enter_in_ring(clouds);
}
enter_in_ring((perfobj_t *) 0); /* 0 indicates end of frame */
buffer = !buffer;
}
}
void enter_in_ring(perfobj_t *perfobj)
{
while (ringbuffer.head == RING_SIZE+ringbuffer.tail-1) {}
ringbuffer.ring[ringbuffer.head % RING_SIZE] = perfobj;
ringbuffer.head++;
}
perfobj_t* get_from_ring(void)
{
static perfobj_t *pobj;
while(ringbuffer.tail == ringbuffer.head) {}
pobj = ringbuffer.ring[ringbuffer.tail % RING_SIZE];
ringbuffer.tail++;
return pobj;
}
/*-------------------------------------- Draw ------------------------------*/
void draw_proc(void)
{
perfobj_t *too_draw;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
while ((too_draw = get_from_ring())) {
drawperfobj(too_draw);
}
}
/*------------------------------- Init -----------------------------------*/
void init_texture_and_lighting(void);
void init_buffered_data(buffered_data *buffered);
void init_misc(void)
{
float density;
threecomp = rgbmode;
/*
* Compute fog and clear color to be linear interpolation between blue
* and white.
*/
density = 1.- expf(-5.5 * fog_density * fog_density *
far_cull * far_cull);
density = MAX(MIN(density, 1.), 0.);
fog_params[0] = .23 + density *.57;
fog_params[1] = .35 + density *.45;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -