Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
|
||||
link_libraries(glfw ${OPENGL_glu_LIBRARY})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_definitions(-DGLFW_DLL)
|
||||
link_libraries(${OPENGL_gl_LIBRARY} ${MATH_LIBRARY})
|
||||
else()
|
||||
link_libraries(${glfw_LIBRARIES})
|
||||
endif()
|
||||
|
||||
include_directories(${GLFW_SOURCE_DIR}/include
|
||||
${GLFW_SOURCE_DIR}/deps)
|
||||
|
||||
if (NOT APPLE)
|
||||
# HACK: This is NOTFOUND on OS X 10.8
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
set(GETOPT ${GLFW_SOURCE_DIR}/deps/getopt.h
|
||||
${GLFW_SOURCE_DIR}/deps/getopt.c)
|
||||
|
||||
if (APPLE)
|
||||
# Set fancy names for bundles
|
||||
add_executable(Boing MACOSX_BUNDLE boing.c)
|
||||
add_executable(Gears MACOSX_BUNDLE gears.c)
|
||||
add_executable(Simple MACOSX_BUNDLE simple.c)
|
||||
add_executable("Split View" MACOSX_BUNDLE splitview.c)
|
||||
add_executable(Wave MACOSX_BUNDLE wave.c)
|
||||
|
||||
set_target_properties(Boing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Boing")
|
||||
set_target_properties(Gears PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gears")
|
||||
set_target_properties(Simple PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Simple")
|
||||
set_target_properties("Split View" PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Split View")
|
||||
set_target_properties(Wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave")
|
||||
else()
|
||||
# Set boring names for executables
|
||||
add_executable(boing WIN32 boing.c)
|
||||
add_executable(gears WIN32 gears.c)
|
||||
add_executable(heightmap WIN32 heightmap.c ${GETOPT})
|
||||
add_executable(simple WIN32 simple.c)
|
||||
add_executable(splitview WIN32 splitview.c)
|
||||
add_executable(wave WIN32 wave.c)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set(WINDOWS_BINARIES boing gears heightmap simple splitview wave)
|
||||
|
||||
# Tell MSVC to use main instead of WinMain for Windows subsystem executables
|
||||
set_target_properties(${WINDOWS_BINARIES} PROPERTIES
|
||||
LINK_FLAGS "/ENTRY:mainCRTStartup")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(BUNDLE_BINARIES Boing Gears Simple "Split View" Wave)
|
||||
|
||||
set_target_properties(${BUNDLE_BINARIES} PROPERTIES
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION}
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION_FULL})
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,628 @@
|
||||
/*****************************************************************************
|
||||
* Title: GLBoing
|
||||
* Desc: Tribute to Amiga Boing.
|
||||
* Author: Jim Brooks <gfx@jimbrooks.org>
|
||||
* Original Amiga authors were R.J. Mical and Dale Luck.
|
||||
* GLFW conversion by Marcus Geelnard
|
||||
* Notes: - 360' = 2*PI [radian]
|
||||
*
|
||||
* - Distances between objects are created by doing a relative
|
||||
* Z translations.
|
||||
*
|
||||
* - Although OpenGL enticingly supports alpha-blending,
|
||||
* the shadow of the original Boing didn't affect the color
|
||||
* of the grid.
|
||||
*
|
||||
* - [Marcus] Changed timing scheme from interval driven to frame-
|
||||
* time based animation steps (which results in much smoother
|
||||
* movement)
|
||||
*
|
||||
* History of Amiga Boing:
|
||||
*
|
||||
* Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in
|
||||
* 1985. According to legend, it was written ad-hoc in one night by
|
||||
* R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast
|
||||
* and smooth, attendees did not believe the Amiga prototype was really doing
|
||||
* the rendering. Suspecting a trick, they began looking around the booth for
|
||||
* a hidden computer or VCR.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define GLFW_INCLUDE_GLU
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Various declarations and macros
|
||||
*****************************************************************************/
|
||||
|
||||
/* Prototypes */
|
||||
void init( void );
|
||||
void display( void );
|
||||
void reshape( GLFWwindow* window, int w, int h );
|
||||
void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods );
|
||||
void DrawBoingBall( void );
|
||||
void BounceBall( double dt );
|
||||
void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi );
|
||||
void DrawGrid( void );
|
||||
|
||||
#define RADIUS 70.f
|
||||
#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */
|
||||
#define STEP_LATITUDE 22.5f
|
||||
|
||||
#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f)
|
||||
|
||||
#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */
|
||||
#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */
|
||||
#define BOUNCE_HEIGHT (RADIUS * 2.1f)
|
||||
#define BOUNCE_WIDTH (RADIUS * 2.1f)
|
||||
|
||||
#define SHADOW_OFFSET_X -20.f
|
||||
#define SHADOW_OFFSET_Y 10.f
|
||||
#define SHADOW_OFFSET_Z 0.f
|
||||
|
||||
#define WALL_L_OFFSET 0.f
|
||||
#define WALL_R_OFFSET 5.f
|
||||
|
||||
/* Animation speed (50.0 mimics the original GLUT demo speed) */
|
||||
#define ANIMATION_SPEED 50.f
|
||||
|
||||
/* Maximum allowed delta time per physics iteration */
|
||||
#define MAX_DELTA_T 0.02f
|
||||
|
||||
/* Draw ball, or its shadow */
|
||||
typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM;
|
||||
|
||||
/* Vertex type */
|
||||
typedef struct {float x; float y; float z;} vertex_t;
|
||||
|
||||
/* Global vars */
|
||||
GLfloat deg_rot_y = 0.f;
|
||||
GLfloat deg_rot_y_inc = 2.f;
|
||||
GLfloat ball_x = -RADIUS;
|
||||
GLfloat ball_y = -RADIUS;
|
||||
GLfloat ball_x_inc = 1.f;
|
||||
GLfloat ball_y_inc = 2.f;
|
||||
DRAW_BALL_ENUM drawBallHow;
|
||||
double t;
|
||||
double t_old = 0.f;
|
||||
double dt;
|
||||
|
||||
/* Random number generator */
|
||||
#ifndef RAND_MAX
|
||||
#define RAND_MAX 4095
|
||||
#endif
|
||||
|
||||
/* PI */
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Truncate a degree.
|
||||
*****************************************************************************/
|
||||
GLfloat TruncateDeg( GLfloat deg )
|
||||
{
|
||||
if ( deg >= 360.f )
|
||||
return (deg - 360.f);
|
||||
else
|
||||
return deg;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Convert a degree (360-based) into a radian.
|
||||
* 360' = 2 * PI
|
||||
*****************************************************************************/
|
||||
double deg2rad( double deg )
|
||||
{
|
||||
return deg / 360 * (2 * M_PI);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* 360' sin().
|
||||
*****************************************************************************/
|
||||
double sin_deg( double deg )
|
||||
{
|
||||
return sin( deg2rad( deg ) );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* 360' cos().
|
||||
*****************************************************************************/
|
||||
double cos_deg( double deg )
|
||||
{
|
||||
return cos( deg2rad( deg ) );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Compute a cross product (for a normal vector).
|
||||
*
|
||||
* c = a x b
|
||||
*****************************************************************************/
|
||||
void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n )
|
||||
{
|
||||
GLfloat u1, u2, u3;
|
||||
GLfloat v1, v2, v3;
|
||||
|
||||
u1 = b.x - a.x;
|
||||
u2 = b.y - a.y;
|
||||
u3 = b.y - a.z;
|
||||
|
||||
v1 = c.x - a.x;
|
||||
v2 = c.y - a.y;
|
||||
v3 = c.z - a.z;
|
||||
|
||||
n->x = u2 * v3 - v2 * v3;
|
||||
n->y = u3 * v1 - v3 * u1;
|
||||
n->z = u1 * v2 - v1 * u2;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Calculate the angle to be passed to gluPerspective() so that a scene
|
||||
* is visible. This function originates from the OpenGL Red Book.
|
||||
*
|
||||
* Parms : size
|
||||
* The size of the segment when the angle is intersected at "dist"
|
||||
* (ie at the outermost edge of the angle of vision).
|
||||
*
|
||||
* dist
|
||||
* Distance from viewpoint to scene.
|
||||
*****************************************************************************/
|
||||
GLfloat PerspectiveAngle( GLfloat size,
|
||||
GLfloat dist )
|
||||
{
|
||||
GLfloat radTheta, degTheta;
|
||||
|
||||
radTheta = 2.f * (GLfloat) atan2( size / 2.f, dist );
|
||||
degTheta = (180.f * radTheta) / (GLfloat) M_PI;
|
||||
return degTheta;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define BOING_DEBUG 0
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* init()
|
||||
*****************************************************************************/
|
||||
void init( void )
|
||||
{
|
||||
/*
|
||||
* Clear background.
|
||||
*/
|
||||
glClearColor( 0.55f, 0.55f, 0.55f, 0.f );
|
||||
|
||||
glShadeModel( GL_FLAT );
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* display()
|
||||
*****************************************************************************/
|
||||
void display(void)
|
||||
{
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
glPushMatrix();
|
||||
|
||||
drawBallHow = DRAW_BALL_SHADOW;
|
||||
DrawBoingBall();
|
||||
|
||||
DrawGrid();
|
||||
|
||||
drawBallHow = DRAW_BALL;
|
||||
DrawBoingBall();
|
||||
|
||||
glPopMatrix();
|
||||
glFlush();
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* reshape()
|
||||
*****************************************************************************/
|
||||
void reshape( GLFWwindow* window, int w, int h )
|
||||
{
|
||||
glViewport( 0, 0, (GLsizei)w, (GLsizei)h );
|
||||
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
|
||||
gluPerspective( PerspectiveAngle( RADIUS * 2, 200 ),
|
||||
(GLfloat)w / (GLfloat)h,
|
||||
1.0,
|
||||
VIEW_SCENE_DIST );
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
|
||||
gluLookAt( 0.0, 0.0, VIEW_SCENE_DIST,/* eye */
|
||||
0.0, 0.0, 0.0, /* center of vision */
|
||||
0.0, -1.0, 0.0 ); /* up vector */
|
||||
}
|
||||
|
||||
void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods )
|
||||
{
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Draw the Boing ball.
|
||||
*
|
||||
* The Boing ball is sphere in which each facet is a rectangle.
|
||||
* Facet colors alternate between red and white.
|
||||
* The ball is built by stacking latitudinal circles. Each circle is composed
|
||||
* of a widely-separated set of points, so that each facet is noticably large.
|
||||
*****************************************************************************/
|
||||
void DrawBoingBall( void )
|
||||
{
|
||||
GLfloat lon_deg; /* degree of longitude */
|
||||
double dt_total, dt2;
|
||||
|
||||
glPushMatrix();
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
|
||||
/*
|
||||
* Another relative Z translation to separate objects.
|
||||
*/
|
||||
glTranslatef( 0.0, 0.0, DIST_BALL );
|
||||
|
||||
/* Update ball position and rotation (iterate if necessary) */
|
||||
dt_total = dt;
|
||||
while( dt_total > 0.0 )
|
||||
{
|
||||
dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total;
|
||||
dt_total -= dt2;
|
||||
BounceBall( dt2 );
|
||||
deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) );
|
||||
}
|
||||
|
||||
/* Set ball position */
|
||||
glTranslatef( ball_x, ball_y, 0.0 );
|
||||
|
||||
/*
|
||||
* Offset the shadow.
|
||||
*/
|
||||
if ( drawBallHow == DRAW_BALL_SHADOW )
|
||||
{
|
||||
glTranslatef( SHADOW_OFFSET_X,
|
||||
SHADOW_OFFSET_Y,
|
||||
SHADOW_OFFSET_Z );
|
||||
}
|
||||
|
||||
/*
|
||||
* Tilt the ball.
|
||||
*/
|
||||
glRotatef( -20.0, 0.0, 0.0, 1.0 );
|
||||
|
||||
/*
|
||||
* Continually rotate ball around Y axis.
|
||||
*/
|
||||
glRotatef( deg_rot_y, 0.0, 1.0, 0.0 );
|
||||
|
||||
/*
|
||||
* Set OpenGL state for Boing ball.
|
||||
*/
|
||||
glCullFace( GL_FRONT );
|
||||
glEnable( GL_CULL_FACE );
|
||||
glEnable( GL_NORMALIZE );
|
||||
|
||||
/*
|
||||
* Build a faceted latitude slice of the Boing ball,
|
||||
* stepping same-sized vertical bands of the sphere.
|
||||
*/
|
||||
for ( lon_deg = 0;
|
||||
lon_deg < 180;
|
||||
lon_deg += STEP_LONGITUDE )
|
||||
{
|
||||
/*
|
||||
* Draw a latitude circle at this longitude.
|
||||
*/
|
||||
DrawBoingBallBand( lon_deg,
|
||||
lon_deg + STEP_LONGITUDE );
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Bounce the ball.
|
||||
*****************************************************************************/
|
||||
void BounceBall( double delta_t )
|
||||
{
|
||||
GLfloat sign;
|
||||
GLfloat deg;
|
||||
|
||||
/* Bounce on walls */
|
||||
if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) )
|
||||
{
|
||||
ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX;
|
||||
deg_rot_y_inc = -deg_rot_y_inc;
|
||||
}
|
||||
if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) )
|
||||
{
|
||||
ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX;
|
||||
deg_rot_y_inc = -deg_rot_y_inc;
|
||||
}
|
||||
|
||||
/* Bounce on floor / roof */
|
||||
if ( ball_y > BOUNCE_HEIGHT/2 )
|
||||
{
|
||||
ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX;
|
||||
}
|
||||
if ( ball_y < -BOUNCE_HEIGHT/2*0.85 )
|
||||
{
|
||||
ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX;
|
||||
}
|
||||
|
||||
/* Update ball position */
|
||||
ball_x += ball_x_inc * ((float)delta_t*ANIMATION_SPEED);
|
||||
ball_y += ball_y_inc * ((float)delta_t*ANIMATION_SPEED);
|
||||
|
||||
/*
|
||||
* Simulate the effects of gravity on Y movement.
|
||||
*/
|
||||
if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0;
|
||||
|
||||
deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT;
|
||||
if ( deg > 80 ) deg = 80;
|
||||
if ( deg < 10 ) deg = 10;
|
||||
|
||||
ball_y_inc = sign * 4.f * (float) sin_deg( deg );
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Draw a faceted latitude band of the Boing ball.
|
||||
*
|
||||
* Parms: long_lo, long_hi
|
||||
* Low and high longitudes of slice, resp.
|
||||
*****************************************************************************/
|
||||
void DrawBoingBallBand( GLfloat long_lo,
|
||||
GLfloat long_hi )
|
||||
{
|
||||
vertex_t vert_ne; /* "ne" means south-east, so on */
|
||||
vertex_t vert_nw;
|
||||
vertex_t vert_sw;
|
||||
vertex_t vert_se;
|
||||
vertex_t vert_norm;
|
||||
GLfloat lat_deg;
|
||||
static int colorToggle = 0;
|
||||
|
||||
/*
|
||||
* Iterate thru the points of a latitude circle.
|
||||
* A latitude circle is a 2D set of X,Z points.
|
||||
*/
|
||||
for ( lat_deg = 0;
|
||||
lat_deg <= (360 - STEP_LATITUDE);
|
||||
lat_deg += STEP_LATITUDE )
|
||||
{
|
||||
/*
|
||||
* Color this polygon with red or white.
|
||||
*/
|
||||
if ( colorToggle )
|
||||
glColor3f( 0.8f, 0.1f, 0.1f );
|
||||
else
|
||||
glColor3f( 0.95f, 0.95f, 0.95f );
|
||||
#if 0
|
||||
if ( lat_deg >= 180 )
|
||||
if ( colorToggle )
|
||||
glColor3f( 0.1f, 0.8f, 0.1f );
|
||||
else
|
||||
glColor3f( 0.5f, 0.5f, 0.95f );
|
||||
#endif
|
||||
colorToggle = ! colorToggle;
|
||||
|
||||
/*
|
||||
* Change color if drawing shadow.
|
||||
*/
|
||||
if ( drawBallHow == DRAW_BALL_SHADOW )
|
||||
glColor3f( 0.35f, 0.35f, 0.35f );
|
||||
|
||||
/*
|
||||
* Assign each Y.
|
||||
*/
|
||||
vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS;
|
||||
vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS;
|
||||
|
||||
/*
|
||||
* Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude.
|
||||
* Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude),
|
||||
* while long=90 (sin(90)=1) is at equator.
|
||||
*/
|
||||
vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE ));
|
||||
vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo ));
|
||||
vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE ));
|
||||
vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo ));
|
||||
|
||||
vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE ));
|
||||
vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo ));
|
||||
vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE ));
|
||||
vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo ));
|
||||
|
||||
/*
|
||||
* Draw the facet.
|
||||
*/
|
||||
glBegin( GL_POLYGON );
|
||||
|
||||
CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm );
|
||||
glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z );
|
||||
|
||||
glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z );
|
||||
glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z );
|
||||
glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z );
|
||||
glVertex3f( vert_se.x, vert_se.y, vert_se.z );
|
||||
|
||||
glEnd();
|
||||
|
||||
#if BOING_DEBUG
|
||||
printf( "----------------------------------------------------------- \n" );
|
||||
printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi );
|
||||
printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z );
|
||||
printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z );
|
||||
printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z );
|
||||
printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Toggle color so that next band will opposite red/white colors than this one.
|
||||
*/
|
||||
colorToggle = ! colorToggle;
|
||||
|
||||
/*
|
||||
* This circular band is done.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Draw the purple grid of lines, behind the Boing ball.
|
||||
* When the Workbench is dropped to the bottom, Boing shows 12 rows.
|
||||
*****************************************************************************/
|
||||
void DrawGrid( void )
|
||||
{
|
||||
int row, col;
|
||||
const int rowTotal = 12; /* must be divisible by 2 */
|
||||
const int colTotal = rowTotal; /* must be same as rowTotal */
|
||||
const GLfloat widthLine = 2.0; /* should be divisible by 2 */
|
||||
const GLfloat sizeCell = GRID_SIZE / rowTotal;
|
||||
const GLfloat z_offset = -40.0;
|
||||
GLfloat xl, xr;
|
||||
GLfloat yt, yb;
|
||||
|
||||
glPushMatrix();
|
||||
glDisable( GL_CULL_FACE );
|
||||
|
||||
/*
|
||||
* Another relative Z translation to separate objects.
|
||||
*/
|
||||
glTranslatef( 0.0, 0.0, DIST_BALL );
|
||||
|
||||
/*
|
||||
* Draw vertical lines (as skinny 3D rectangles).
|
||||
*/
|
||||
for ( col = 0; col <= colTotal; col++ )
|
||||
{
|
||||
/*
|
||||
* Compute co-ords of line.
|
||||
*/
|
||||
xl = -GRID_SIZE / 2 + col * sizeCell;
|
||||
xr = xl + widthLine;
|
||||
|
||||
yt = GRID_SIZE / 2;
|
||||
yb = -GRID_SIZE / 2 - widthLine;
|
||||
|
||||
glBegin( GL_POLYGON );
|
||||
|
||||
glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */
|
||||
|
||||
glVertex3f( xr, yt, z_offset ); /* NE */
|
||||
glVertex3f( xl, yt, z_offset ); /* NW */
|
||||
glVertex3f( xl, yb, z_offset ); /* SW */
|
||||
glVertex3f( xr, yb, z_offset ); /* SE */
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw horizontal lines (as skinny 3D rectangles).
|
||||
*/
|
||||
for ( row = 0; row <= rowTotal; row++ )
|
||||
{
|
||||
/*
|
||||
* Compute co-ords of line.
|
||||
*/
|
||||
yt = GRID_SIZE / 2 - row * sizeCell;
|
||||
yb = yt - widthLine;
|
||||
|
||||
xl = -GRID_SIZE / 2;
|
||||
xr = GRID_SIZE / 2 + widthLine;
|
||||
|
||||
glBegin( GL_POLYGON );
|
||||
|
||||
glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */
|
||||
|
||||
glVertex3f( xr, yt, z_offset ); /* NE */
|
||||
glVertex3f( xl, yt, z_offset ); /* NW */
|
||||
glVertex3f( xl, yb, z_offset ); /* SW */
|
||||
glVertex3f( xr, yb, z_offset ); /* SE */
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*======================================================================*
|
||||
* main()
|
||||
*======================================================================*/
|
||||
|
||||
int main( void )
|
||||
{
|
||||
GLFWwindow* window;
|
||||
int width, height;
|
||||
|
||||
/* Init GLFW */
|
||||
if( !glfwInit() )
|
||||
exit( EXIT_FAILURE );
|
||||
|
||||
glfwWindowHint(GLFW_DEPTH_BITS, 16);
|
||||
|
||||
window = glfwCreateWindow( 400, 400, "Boing (classic Amiga demo)", NULL, NULL );
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
glfwSetFramebufferSizeCallback(window, reshape);
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval( 1 );
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
reshape(window, width, height);
|
||||
|
||||
glfwSetTime( 0.0 );
|
||||
|
||||
init();
|
||||
|
||||
/* Main loop */
|
||||
for (;;)
|
||||
{
|
||||
/* Timing */
|
||||
t = glfwGetTime();
|
||||
dt = t - t_old;
|
||||
t_old = t;
|
||||
|
||||
/* Draw one frame */
|
||||
display();
|
||||
|
||||
/* Swap buffers */
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
|
||||
/* Check if we are still running */
|
||||
if (glfwWindowShouldClose(window))
|
||||
break;
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* 3-D gear wheels. This program is in the public domain.
|
||||
*
|
||||
* Command line options:
|
||||
* -info print GL implementation information
|
||||
* -exit automatically exit after 30 seconds
|
||||
*
|
||||
*
|
||||
* Brian Paul
|
||||
*
|
||||
*
|
||||
* Marcus Geelnard:
|
||||
* - Conversion to GLFW
|
||||
* - Time based rendering (frame rate independent)
|
||||
* - Slightly modified camera that should work better for stereo viewing
|
||||
*
|
||||
*
|
||||
* Camilla Berglund:
|
||||
* - Removed FPS counter (this is not a benchmark)
|
||||
* - Added a few comments
|
||||
* - Enabled vsync
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592654
|
||||
#endif
|
||||
|
||||
/* If non-zero, the program exits after that many seconds
|
||||
*/
|
||||
static int autoexit = 0;
|
||||
|
||||
/**
|
||||
|
||||
Draw a gear wheel. You'll probably want to call this function when
|
||||
building a display list since we do a lot of trig here.
|
||||
|
||||
Input: inner_radius - radius of hole at center
|
||||
outer_radius - radius at center of teeth
|
||||
width - width of gear teeth - number of teeth
|
||||
tooth_depth - depth of tooth
|
||||
|
||||
**/
|
||||
|
||||
static void
|
||||
gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
|
||||
GLint teeth, GLfloat tooth_depth)
|
||||
{
|
||||
GLint i;
|
||||
GLfloat r0, r1, r2;
|
||||
GLfloat angle, da;
|
||||
GLfloat u, v, len;
|
||||
|
||||
r0 = inner_radius;
|
||||
r1 = outer_radius - tooth_depth / 2.f;
|
||||
r2 = outer_radius + tooth_depth / 2.f;
|
||||
|
||||
da = 2.f * (float) M_PI / teeth / 4.f;
|
||||
|
||||
glShadeModel(GL_FLAT);
|
||||
|
||||
glNormal3f(0.f, 0.f, 1.f);
|
||||
|
||||
/* draw front face */
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++) {
|
||||
angle = i * 2.f * (float) M_PI / teeth;
|
||||
glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f);
|
||||
glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f);
|
||||
if (i < teeth) {
|
||||
glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f);
|
||||
glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
/* draw front sides of teeth */
|
||||
glBegin(GL_QUADS);
|
||||
da = 2.f * (float) M_PI / teeth / 4.f;
|
||||
for (i = 0; i < teeth; i++) {
|
||||
angle = i * 2.f * (float) M_PI / teeth;
|
||||
|
||||
glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f);
|
||||
glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f);
|
||||
glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f);
|
||||
glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glNormal3f(0.0, 0.0, -1.0);
|
||||
|
||||
/* draw back face */
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++) {
|
||||
angle = i * 2.f * (float) M_PI / teeth;
|
||||
glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f);
|
||||
glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f);
|
||||
if (i < teeth) {
|
||||
glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f);
|
||||
glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
/* draw back sides of teeth */
|
||||
glBegin(GL_QUADS);
|
||||
da = 2.f * (float) M_PI / teeth / 4.f;
|
||||
for (i = 0; i < teeth; i++) {
|
||||
angle = i * 2.f * (float) M_PI / teeth;
|
||||
|
||||
glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f);
|
||||
glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f);
|
||||
glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f);
|
||||
glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
/* draw outward faces of teeth */
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i < teeth; i++) {
|
||||
angle = i * 2.f * (float) M_PI / teeth;
|
||||
|
||||
glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f);
|
||||
glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f);
|
||||
u = r2 * (float) cos(angle + da) - r1 * (float) cos(angle);
|
||||
v = r2 * (float) sin(angle + da) - r1 * (float) sin(angle);
|
||||
len = (float) sqrt(u * u + v * v);
|
||||
u /= len;
|
||||
v /= len;
|
||||
glNormal3f(v, -u, 0.0);
|
||||
glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f);
|
||||
glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f);
|
||||
glNormal3f((float) cos(angle), (float) sin(angle), 0.f);
|
||||
glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f);
|
||||
glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f);
|
||||
u = r1 * (float) cos(angle + 3 * da) - r2 * (float) cos(angle + 2 * da);
|
||||
v = r1 * (float) sin(angle + 3 * da) - r2 * (float) sin(angle + 2 * da);
|
||||
glNormal3f(v, -u, 0.f);
|
||||
glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f);
|
||||
glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f);
|
||||
glNormal3f((float) cos(angle), (float) sin(angle), 0.f);
|
||||
}
|
||||
|
||||
glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), width * 0.5f);
|
||||
glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), -width * 0.5f);
|
||||
|
||||
glEnd();
|
||||
|
||||
glShadeModel(GL_SMOOTH);
|
||||
|
||||
/* draw inside radius cylinder */
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++) {
|
||||
angle = i * 2.f * (float) M_PI / teeth;
|
||||
glNormal3f(-(float) cos(angle), -(float) sin(angle), 0.f);
|
||||
glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f);
|
||||
glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
}
|
||||
|
||||
|
||||
static GLfloat view_rotx = 20.f, view_roty = 30.f, view_rotz = 0.f;
|
||||
static GLint gear1, gear2, gear3;
|
||||
static GLfloat angle = 0.f;
|
||||
|
||||
/* OpenGL draw function & timing */
|
||||
static void draw(void)
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix();
|
||||
glRotatef(view_rotx, 1.0, 0.0, 0.0);
|
||||
glRotatef(view_roty, 0.0, 1.0, 0.0);
|
||||
glRotatef(view_rotz, 0.0, 0.0, 1.0);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-3.0, -2.0, 0.0);
|
||||
glRotatef(angle, 0.0, 0.0, 1.0);
|
||||
glCallList(gear1);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(3.1f, -2.f, 0.f);
|
||||
glRotatef(-2.f * angle - 9.f, 0.f, 0.f, 1.f);
|
||||
glCallList(gear2);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-3.1f, 4.2f, 0.f);
|
||||
glRotatef(-2.f * angle - 25.f, 0.f, 0.f, 1.f);
|
||||
glCallList(gear3);
|
||||
glPopMatrix();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
/* update animation parameters */
|
||||
static void animate(void)
|
||||
{
|
||||
angle = 100.f * (float) glfwGetTime();
|
||||
}
|
||||
|
||||
|
||||
/* change view angle, exit upon ESC */
|
||||
void key( GLFWwindow* window, int k, int s, int action, int mods )
|
||||
{
|
||||
if( action != GLFW_PRESS ) return;
|
||||
|
||||
switch (k) {
|
||||
case GLFW_KEY_Z:
|
||||
if( mods & GLFW_MOD_SHIFT )
|
||||
view_rotz -= 5.0;
|
||||
else
|
||||
view_rotz += 5.0;
|
||||
break;
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
break;
|
||||
case GLFW_KEY_UP:
|
||||
view_rotx += 5.0;
|
||||
break;
|
||||
case GLFW_KEY_DOWN:
|
||||
view_rotx -= 5.0;
|
||||
break;
|
||||
case GLFW_KEY_LEFT:
|
||||
view_roty += 5.0;
|
||||
break;
|
||||
case GLFW_KEY_RIGHT:
|
||||
view_roty -= 5.0;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* new window size */
|
||||
void reshape( GLFWwindow* window, int width, int height )
|
||||
{
|
||||
GLfloat h = (GLfloat) height / (GLfloat) width;
|
||||
GLfloat xmax, znear, zfar;
|
||||
|
||||
znear = 5.0f;
|
||||
zfar = 30.0f;
|
||||
xmax = znear * 0.5f;
|
||||
|
||||
glViewport( 0, 0, (GLint) width, (GLint) height );
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
glFrustum( -xmax, xmax, -xmax*h, xmax*h, znear, zfar );
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
glTranslatef( 0.0, 0.0, -20.0 );
|
||||
}
|
||||
|
||||
|
||||
/* program & OpenGL initialization */
|
||||
static void init(int argc, char *argv[])
|
||||
{
|
||||
static GLfloat pos[4] = {5.f, 5.f, 10.f, 0.f};
|
||||
static GLfloat red[4] = {0.8f, 0.1f, 0.f, 1.f};
|
||||
static GLfloat green[4] = {0.f, 0.8f, 0.2f, 1.f};
|
||||
static GLfloat blue[4] = {0.2f, 0.2f, 1.f, 1.f};
|
||||
GLint i;
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, pos);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
/* make the gears */
|
||||
gear1 = glGenLists(1);
|
||||
glNewList(gear1, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
|
||||
gear(1.f, 4.f, 1.f, 20, 0.7f);
|
||||
glEndList();
|
||||
|
||||
gear2 = glGenLists(1);
|
||||
glNewList(gear2, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
|
||||
gear(0.5f, 2.f, 2.f, 10, 0.7f);
|
||||
glEndList();
|
||||
|
||||
gear3 = glGenLists(1);
|
||||
glNewList(gear3, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
|
||||
gear(1.3f, 2.f, 0.5f, 10, 0.7f);
|
||||
glEndList();
|
||||
|
||||
glEnable(GL_NORMALIZE);
|
||||
|
||||
for ( i=1; i<argc; i++ ) {
|
||||
if (strcmp(argv[i], "-info")==0) {
|
||||
printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
|
||||
printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
|
||||
printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
|
||||
printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
|
||||
}
|
||||
else if ( strcmp(argv[i], "-exit")==0) {
|
||||
autoexit = 30;
|
||||
printf("Auto Exit after %i seconds.\n", autoexit );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* program entry */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
GLFWwindow* window;
|
||||
int width, height;
|
||||
|
||||
if( !glfwInit() )
|
||||
{
|
||||
fprintf( stderr, "Failed to initialize GLFW\n" );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_DEPTH_BITS, 16);
|
||||
|
||||
window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL );
|
||||
if (!window)
|
||||
{
|
||||
fprintf( stderr, "Failed to open GLFW window\n" );
|
||||
glfwTerminate();
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
// Set callback functions
|
||||
glfwSetFramebufferSizeCallback(window, reshape);
|
||||
glfwSetKeyCallback(window, key);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval( 1 );
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
reshape(window, width, height);
|
||||
|
||||
// Parse command-line options
|
||||
init(argc, argv);
|
||||
|
||||
// Main loop
|
||||
while( !glfwWindowShouldClose(window) )
|
||||
{
|
||||
// Draw gears
|
||||
draw();
|
||||
|
||||
// Update animation
|
||||
animate();
|
||||
|
||||
// Swap buffers
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
// Terminate GLFW
|
||||
glfwTerminate();
|
||||
|
||||
// Exit program
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,678 @@
|
||||
//========================================================================
|
||||
// Heightmap example program using OpenGL 3 core profile
|
||||
// Copyright (c) 2010 Olivier Delannoy
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include "getopt.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
/* OpenGL function pointers */
|
||||
static PFNGLGENBUFFERSPROC pglGenBuffers = NULL;
|
||||
static PFNGLGENVERTEXARRAYSPROC pglGenVertexArrays = NULL;
|
||||
static PFNGLDELETEVERTEXARRAYSPROC pglDeleteVertexArrays = NULL;
|
||||
static PFNGLCREATESHADERPROC pglCreateShader = NULL;
|
||||
static PFNGLSHADERSOURCEPROC pglShaderSource = NULL;
|
||||
static PFNGLCOMPILESHADERPROC pglCompileShader = NULL;
|
||||
static PFNGLGETSHADERIVPROC pglGetShaderiv = NULL;
|
||||
static PFNGLGETSHADERINFOLOGPROC pglGetShaderInfoLog = NULL;
|
||||
static PFNGLDELETESHADERPROC pglDeleteShader = NULL;
|
||||
static PFNGLCREATEPROGRAMPROC pglCreateProgram = NULL;
|
||||
static PFNGLATTACHSHADERPROC pglAttachShader = NULL;
|
||||
static PFNGLLINKPROGRAMPROC pglLinkProgram = NULL;
|
||||
static PFNGLUSEPROGRAMPROC pglUseProgram = NULL;
|
||||
static PFNGLGETPROGRAMIVPROC pglGetProgramiv = NULL;
|
||||
static PFNGLGETPROGRAMINFOLOGPROC pglGetProgramInfoLog = NULL;
|
||||
static PFNGLDELETEPROGRAMPROC pglDeleteProgram = NULL;
|
||||
static PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation = NULL;
|
||||
static PFNGLUNIFORMMATRIX4FVPROC pglUniformMatrix4fv = NULL;
|
||||
static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation = NULL;
|
||||
static PFNGLBINDVERTEXARRAYPROC pglBindVertexArray = NULL;
|
||||
static PFNGLBUFFERDATAPROC pglBufferData = NULL;
|
||||
static PFNGLBINDBUFFERPROC pglBindBuffer = NULL;
|
||||
static PFNGLBUFFERSUBDATAPROC pglBufferSubData = NULL;
|
||||
static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray = NULL;
|
||||
static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer = NULL;
|
||||
|
||||
/* Map height updates */
|
||||
#define MAX_CIRCLE_SIZE (5.0f)
|
||||
#define MAX_DISPLACEMENT (1.0f)
|
||||
#define DISPLACEMENT_SIGN_LIMIT (0.3f)
|
||||
#define MAX_ITER (200)
|
||||
#define NUM_ITER_AT_A_TIME (1)
|
||||
|
||||
/* Map general information */
|
||||
#define MAP_SIZE (10.0f)
|
||||
#define MAP_NUM_VERTICES (80)
|
||||
#define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES)
|
||||
#define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \
|
||||
2 * (MAP_NUM_VERTICES - 1))
|
||||
|
||||
|
||||
/* OpenGL function pointers */
|
||||
|
||||
#define RESOLVE_GL_FCN(type, var, name) \
|
||||
if (status == GL_TRUE) \
|
||||
{\
|
||||
var = (type) glfwGetProcAddress((name));\
|
||||
if ((var) == NULL)\
|
||||
{\
|
||||
status = GL_FALSE;\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
static GLboolean init_opengl(void)
|
||||
{
|
||||
GLboolean status = GL_TRUE;
|
||||
RESOLVE_GL_FCN(PFNGLCREATESHADERPROC, pglCreateShader, "glCreateShader");
|
||||
RESOLVE_GL_FCN(PFNGLSHADERSOURCEPROC, pglShaderSource, "glShaderSource");
|
||||
RESOLVE_GL_FCN(PFNGLCOMPILESHADERPROC, pglCompileShader, "glCompileShader");
|
||||
RESOLVE_GL_FCN(PFNGLGETSHADERIVPROC, pglGetShaderiv, "glGetShaderiv");
|
||||
RESOLVE_GL_FCN(PFNGLGETSHADERINFOLOGPROC, pglGetShaderInfoLog, "glGetShaderInfoLog");
|
||||
RESOLVE_GL_FCN(PFNGLDELETESHADERPROC, pglDeleteShader, "glDeleteShader");
|
||||
RESOLVE_GL_FCN(PFNGLCREATEPROGRAMPROC, pglCreateProgram, "glCreateProgram");
|
||||
RESOLVE_GL_FCN(PFNGLATTACHSHADERPROC, pglAttachShader, "glAttachShader");
|
||||
RESOLVE_GL_FCN(PFNGLLINKPROGRAMPROC, pglLinkProgram, "glLinkProgram");
|
||||
RESOLVE_GL_FCN(PFNGLUSEPROGRAMPROC, pglUseProgram, "glUseProgram");
|
||||
RESOLVE_GL_FCN(PFNGLGETPROGRAMIVPROC, pglGetProgramiv, "glGetProgramiv");
|
||||
RESOLVE_GL_FCN(PFNGLGETPROGRAMINFOLOGPROC, pglGetProgramInfoLog, "glGetProgramInfoLog");
|
||||
RESOLVE_GL_FCN(PFNGLDELETEPROGRAMPROC, pglDeleteProgram, "glDeleteProgram");
|
||||
RESOLVE_GL_FCN(PFNGLGETUNIFORMLOCATIONPROC, pglGetUniformLocation, "glGetUniformLocation");
|
||||
RESOLVE_GL_FCN(PFNGLUNIFORMMATRIX4FVPROC, pglUniformMatrix4fv, "glUniformMatrix4fv");
|
||||
RESOLVE_GL_FCN(PFNGLGETATTRIBLOCATIONPROC, pglGetAttribLocation, "glGetAttribLocation");
|
||||
RESOLVE_GL_FCN(PFNGLGENVERTEXARRAYSPROC, pglGenVertexArrays, "glGenVertexArrays");
|
||||
RESOLVE_GL_FCN(PFNGLDELETEVERTEXARRAYSPROC, pglDeleteVertexArrays, "glDeleteVertexArrays");
|
||||
RESOLVE_GL_FCN(PFNGLBINDVERTEXARRAYPROC, pglBindVertexArray, "glBindVertexArray");
|
||||
RESOLVE_GL_FCN(PFNGLGENBUFFERSPROC, pglGenBuffers, "glGenBuffers");
|
||||
RESOLVE_GL_FCN(PFNGLBINDBUFFERPROC, pglBindBuffer, "glBindBuffer");
|
||||
RESOLVE_GL_FCN(PFNGLBUFFERDATAPROC, pglBufferData, "glBufferData");
|
||||
RESOLVE_GL_FCN(PFNGLBUFFERSUBDATAPROC, pglBufferSubData, "glBufferSubData");
|
||||
RESOLVE_GL_FCN(PFNGLENABLEVERTEXATTRIBARRAYPROC, pglEnableVertexAttribArray, "glEnableVertexAttribArray");
|
||||
RESOLVE_GL_FCN(PFNGLVERTEXATTRIBPOINTERPROC, pglVertexAttribPointer, "glVertexAttribPointer");
|
||||
return status;
|
||||
}
|
||||
/**********************************************************************
|
||||
* Default shader programs
|
||||
*********************************************************************/
|
||||
|
||||
static const char* default_vertex_shader =
|
||||
"#version 150\n"
|
||||
"uniform mat4 project;\n"
|
||||
"uniform mat4 modelview;\n"
|
||||
"in float x;\n"
|
||||
"in float y;\n"
|
||||
"in float z;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = project * modelview * vec4(x, y, z, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* default_fragment_shader =
|
||||
"#version 150\n"
|
||||
"out vec4 gl_FragColor;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0); \n"
|
||||
"}\n";
|
||||
|
||||
/**********************************************************************
|
||||
* Values for shader uniforms
|
||||
*********************************************************************/
|
||||
|
||||
/* Frustum configuration */
|
||||
static GLfloat view_angle = 45.0f;
|
||||
static GLfloat aspect_ratio = 4.0f/3.0f;
|
||||
static GLfloat z_near = 1.0f;
|
||||
static GLfloat z_far = 100.f;
|
||||
|
||||
/* Projection matrix */
|
||||
static GLfloat projection_matrix[16] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
/* Model view matrix */
|
||||
static GLfloat modelview_matrix[16] = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* Heightmap vertex and index data
|
||||
*********************************************************************/
|
||||
|
||||
static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES];
|
||||
static GLuint map_line_indices[2*MAP_NUM_LINES];
|
||||
|
||||
/* Store uniform location for the shaders
|
||||
* Those values are setup as part of the process of creating
|
||||
* the shader program. They should not be used before creating
|
||||
* the program.
|
||||
*/
|
||||
static GLuint mesh;
|
||||
static GLuint mesh_vbo[4];
|
||||
|
||||
/**********************************************************************
|
||||
* OpenGL helper functions
|
||||
*********************************************************************/
|
||||
|
||||
/* Load a (text) file into memory and return its contents
|
||||
*/
|
||||
static char* read_file_content(const char* filename)
|
||||
{
|
||||
FILE* fd;
|
||||
size_t size = 0;
|
||||
char* result = NULL;
|
||||
|
||||
fd = fopen(filename, "r");
|
||||
if (fd != NULL)
|
||||
{
|
||||
size = fseek(fd, 0, SEEK_END);
|
||||
(void) fseek(fd, 0, SEEK_SET);
|
||||
|
||||
result = malloc(size + 1);
|
||||
result[size] = '\0';
|
||||
if (fread(result, size, 1, fd) != 1)
|
||||
{
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
(void) fclose(fd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Creates a shader object of the specified type using the specified text
|
||||
*/
|
||||
static GLuint make_shader(GLenum type, const char* shader_src)
|
||||
{
|
||||
GLuint shader;
|
||||
GLint shader_ok;
|
||||
GLsizei log_length;
|
||||
char info_log[8192];
|
||||
|
||||
shader = pglCreateShader(type);
|
||||
if (shader != 0)
|
||||
{
|
||||
pglShaderSource(shader, 1, (const GLchar**)&shader_src, NULL);
|
||||
pglCompileShader(shader);
|
||||
pglGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
|
||||
if (shader_ok != GL_TRUE)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" );
|
||||
pglGetShaderInfoLog(shader, 8192, &log_length,info_log);
|
||||
fprintf(stderr, "ERROR: \n%s\n\n", info_log);
|
||||
pglDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
/* Creates a program object using the specified vertex and fragment text
|
||||
*/
|
||||
static GLuint make_shader_program(const char* vertex_shader_src, const char* fragment_shader_src)
|
||||
{
|
||||
GLuint program = 0u;
|
||||
GLint program_ok;
|
||||
GLuint vertex_shader = 0u;
|
||||
GLuint fragment_shader = 0u;
|
||||
GLsizei log_length;
|
||||
char info_log[8192];
|
||||
|
||||
vertex_shader = make_shader(GL_VERTEX_SHADER, (vertex_shader_src == NULL) ? default_vertex_shader : vertex_shader_src);
|
||||
if (vertex_shader != 0u)
|
||||
{
|
||||
fragment_shader = make_shader(GL_FRAGMENT_SHADER, (fragment_shader_src == NULL) ? default_fragment_shader : fragment_shader_src);
|
||||
if (fragment_shader != 0u)
|
||||
{
|
||||
/* make the program that connect the two shader and link it */
|
||||
program = pglCreateProgram();
|
||||
if (program != 0u)
|
||||
{
|
||||
/* attach both shader and link */
|
||||
pglAttachShader(program, vertex_shader);
|
||||
pglAttachShader(program, fragment_shader);
|
||||
pglLinkProgram(program);
|
||||
pglGetProgramiv(program, GL_LINK_STATUS, &program_ok);
|
||||
|
||||
if (program_ok != GL_TRUE)
|
||||
{
|
||||
fprintf(stderr, "ERROR, failed to link shader program\n");
|
||||
pglGetProgramInfoLog(program, 8192, &log_length, info_log);
|
||||
fprintf(stderr, "ERROR: \n%s\n\n", info_log);
|
||||
pglDeleteProgram(program);
|
||||
pglDeleteShader(fragment_shader);
|
||||
pglDeleteShader(vertex_shader);
|
||||
program = 0u;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: Unable to load fragment shader\n");
|
||||
pglDeleteShader(vertex_shader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "ERROR: Unable to load vertex shader\n");
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Geometry creation functions
|
||||
*********************************************************************/
|
||||
|
||||
/* Generate vertices and indices for the heightmap
|
||||
*/
|
||||
static void init_map(void)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1);
|
||||
GLfloat x = 0.0f;
|
||||
GLfloat z = 0.0f;
|
||||
/* Create a flat grid */
|
||||
k = 0;
|
||||
for (i = 0 ; i < MAP_NUM_VERTICES ; ++i)
|
||||
{
|
||||
for (j = 0 ; j < MAP_NUM_VERTICES ; ++j)
|
||||
{
|
||||
map_vertices[0][k] = x;
|
||||
map_vertices[1][k] = 0.0f;
|
||||
map_vertices[2][k] = z;
|
||||
z += step;
|
||||
++k;
|
||||
}
|
||||
x += step;
|
||||
z = 0.0f;
|
||||
}
|
||||
#if DEBUG_ENABLED
|
||||
for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i)
|
||||
{
|
||||
printf ("Vertice %d (%f, %f, %f)\n",
|
||||
i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]);
|
||||
|
||||
}
|
||||
#endif
|
||||
/* create indices */
|
||||
/* line fan based on i
|
||||
* i+1
|
||||
* | / i + n + 1
|
||||
* | /
|
||||
* |/
|
||||
* i --- i + n
|
||||
*/
|
||||
|
||||
/* close the top of the square */
|
||||
k = 0;
|
||||
for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i)
|
||||
{
|
||||
map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1;
|
||||
map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1;
|
||||
}
|
||||
/* close the right of the square */
|
||||
for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i)
|
||||
{
|
||||
map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i;
|
||||
map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i)
|
||||
{
|
||||
for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j)
|
||||
{
|
||||
int ref = i * (MAP_NUM_VERTICES) + j;
|
||||
map_line_indices[k++] = ref;
|
||||
map_line_indices[k++] = ref + 1;
|
||||
|
||||
map_line_indices[k++] = ref;
|
||||
map_line_indices[k++] = ref + MAP_NUM_VERTICES;
|
||||
|
||||
map_line_indices[k++] = ref;
|
||||
map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2)
|
||||
{
|
||||
int beg, end;
|
||||
beg = map_line_indices[k];
|
||||
end = map_line_indices[k+1];
|
||||
printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n",
|
||||
k / 2, beg, end,
|
||||
map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg],
|
||||
map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void generate_heightmap__circle(float* center_x, float* center_y,
|
||||
float* size, float* displacement)
|
||||
{
|
||||
float sign;
|
||||
/* random value for element in between [0-1.0] */
|
||||
*center_x = (MAP_SIZE * rand()) / (1.0f * RAND_MAX);
|
||||
*center_y = (MAP_SIZE * rand()) / (1.0f * RAND_MAX);
|
||||
*size = (MAX_CIRCLE_SIZE * rand()) / (1.0f * RAND_MAX);
|
||||
sign = (1.0f * rand()) / (1.0f * RAND_MAX);
|
||||
sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f;
|
||||
*displacement = (sign * (MAX_DISPLACEMENT * rand())) / (1.0f * RAND_MAX);
|
||||
}
|
||||
|
||||
/* Run the specified number of iterations of the generation process for the
|
||||
* heightmap
|
||||
*/
|
||||
static void update_map(int num_iter)
|
||||
{
|
||||
assert(num_iter > 0);
|
||||
while(num_iter)
|
||||
{
|
||||
/* center of the circle */
|
||||
float center_x;
|
||||
float center_z;
|
||||
float circle_size;
|
||||
float disp;
|
||||
size_t ii;
|
||||
generate_heightmap__circle(¢er_x, ¢er_z, &circle_size, &disp);
|
||||
disp = disp / 2.0f;
|
||||
for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii)
|
||||
{
|
||||
GLfloat dx = center_x - map_vertices[0][ii];
|
||||
GLfloat dz = center_z - map_vertices[2][ii];
|
||||
GLfloat pd = (2.0f * sqrtf((dx * dx) + (dz * dz))) / circle_size;
|
||||
if (fabs(pd) <= 1.0f)
|
||||
{
|
||||
/* tx,tz is within the circle */
|
||||
GLfloat new_height = disp + (float) (cos(pd*3.14f)*disp);
|
||||
map_vertices[1][ii] += new_height;
|
||||
}
|
||||
}
|
||||
--num_iter;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* OpenGL helper functions
|
||||
*********************************************************************/
|
||||
|
||||
/* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to
|
||||
* the specified program object
|
||||
*/
|
||||
static void make_mesh(GLuint program)
|
||||
{
|
||||
GLuint attrloc;
|
||||
|
||||
pglGenVertexArrays(1, &mesh);
|
||||
pglGenBuffers(4, mesh_vbo);
|
||||
pglBindVertexArray(mesh);
|
||||
/* Prepare the data for drawing through a buffer inidices */
|
||||
pglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]);
|
||||
pglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW);
|
||||
|
||||
/* Prepare the attributes for rendering */
|
||||
attrloc = pglGetAttribLocation(program, "x");
|
||||
pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]);
|
||||
pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW);
|
||||
pglEnableVertexAttribArray(attrloc);
|
||||
pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
attrloc = pglGetAttribLocation(program, "z");
|
||||
pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]);
|
||||
pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW);
|
||||
pglEnableVertexAttribArray(attrloc);
|
||||
pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
attrloc = pglGetAttribLocation(program, "y");
|
||||
pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]);
|
||||
pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW);
|
||||
pglEnableVertexAttribArray(attrloc);
|
||||
pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
/* Update VBO vertices from source data
|
||||
*/
|
||||
static void update_mesh(void)
|
||||
{
|
||||
pglBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* GLFW callback functions
|
||||
*********************************************************************/
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case GLFW_KEY_ESCAPE:
|
||||
/* Exit program on Escape */
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print usage information */
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: heightmap [-v <vertex_shader_path>] [-f <fragment_shader_path>]\n");
|
||||
printf(" heightmap [-h]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
GLFWwindow* window;
|
||||
int ch, iter;
|
||||
double dt;
|
||||
double last_update_time;
|
||||
int frame;
|
||||
float f;
|
||||
GLint uloc_modelview;
|
||||
GLint uloc_project;
|
||||
|
||||
char* vertex_shader_path = NULL;
|
||||
char* fragment_shader_path = NULL;
|
||||
char* vertex_shader_src = NULL;
|
||||
char* fragment_shader_src = NULL;
|
||||
GLuint shader_program;
|
||||
|
||||
while ((ch = getopt(argc, argv, "f:v:h")) != -1)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'f':
|
||||
fragment_shader_path = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
vertex_shader_path = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
default:
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (fragment_shader_path)
|
||||
{
|
||||
vertex_shader_src = read_file_content(fragment_shader_path);
|
||||
if (!fragment_shader_src)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"ERROR: unable to load fragment shader from '%s'\n",
|
||||
fragment_shader_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (vertex_shader_path)
|
||||
{
|
||||
vertex_shader_src = read_file_content(vertex_shader_path);
|
||||
if (!vertex_shader_src)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"ERROR: unable to load vertex shader from '%s'\n",
|
||||
fragment_shader_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!glfwInit())
|
||||
{
|
||||
fprintf(stderr, "ERROR: Unable to initialize GLFW\n");
|
||||
usage();
|
||||
|
||||
free(vertex_shader_src);
|
||||
free(fragment_shader_src);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
|
||||
|
||||
window = glfwCreateWindow(800, 600, "GLFW OpenGL3 Heightmap demo", NULL, NULL);
|
||||
if (! window )
|
||||
{
|
||||
fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n");
|
||||
usage();
|
||||
|
||||
free(vertex_shader_src);
|
||||
free(fragment_shader_src);
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Register events callback */
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
if (GL_TRUE != init_opengl())
|
||||
{
|
||||
fprintf(stderr, "ERROR: unable to resolve OpenGL function pointers\n");
|
||||
free(vertex_shader_src);
|
||||
free(fragment_shader_src);
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Prepare opengl resources for rendering */
|
||||
shader_program = make_shader_program(vertex_shader_src , fragment_shader_src);
|
||||
free(vertex_shader_src);
|
||||
free(fragment_shader_src);
|
||||
|
||||
if (shader_program == 0u)
|
||||
{
|
||||
fprintf(stderr, "ERROR: during creation of the shader program\n");
|
||||
usage();
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pglUseProgram(shader_program);
|
||||
uloc_project = pglGetUniformLocation(shader_program, "project");
|
||||
uloc_modelview = pglGetUniformLocation(shader_program, "modelview");
|
||||
|
||||
/* Compute the projection matrix */
|
||||
f = 1.0f / tanf(view_angle / 2.0f);
|
||||
projection_matrix[0] = f / aspect_ratio;
|
||||
projection_matrix[5] = f;
|
||||
projection_matrix[10] = (z_far + z_near)/ (z_near - z_far);
|
||||
projection_matrix[11] = -1.0f;
|
||||
projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far);
|
||||
pglUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix);
|
||||
|
||||
/* Set the camera position */
|
||||
modelview_matrix[12] = -5.0f;
|
||||
modelview_matrix[13] = -5.0f;
|
||||
modelview_matrix[14] = -20.0f;
|
||||
pglUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix);
|
||||
|
||||
/* Create mesh data */
|
||||
init_map();
|
||||
make_mesh(shader_program);
|
||||
|
||||
/* Create vao + vbo to store the mesh */
|
||||
/* Create the vbo to store all the information for the grid and the height */
|
||||
|
||||
/* setup the scene ready for rendering */
|
||||
glViewport(0, 0, 800, 600);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
/* main loop */
|
||||
frame = 0;
|
||||
iter = 0;
|
||||
dt = last_update_time = glfwGetTime();
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
++frame;
|
||||
/* render the next frame */
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0);
|
||||
|
||||
/* display and process events through callbacks */
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
/* Check the frame rate and update the heightmap if needed */
|
||||
dt = glfwGetTime();
|
||||
if ((dt - last_update_time) > 0.2)
|
||||
{
|
||||
/* generate the next iteration of the heightmap */
|
||||
if (iter < MAX_ITER)
|
||||
{
|
||||
update_map(NUM_ITER_AT_A_TIME);
|
||||
update_mesh();
|
||||
iter += NUM_ITER_AT_A_TIME;
|
||||
}
|
||||
last_update_time = dt;
|
||||
frame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
//========================================================================
|
||||
// Simple GLFW example
|
||||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
//! [code]
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
{
|
||||
fputs(description, stderr);
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GLFWwindow* window;
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
float ratio;
|
||||
int width, height;
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
ratio = width / (float) height;
|
||||
|
||||
glViewport(0, 0, width, height);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glLoadIdentity();
|
||||
glRotatef((float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glColor3f(1.f, 0.f, 0.f);
|
||||
glVertex3f(-0.6f, -0.4f, 0.f);
|
||||
glColor3f(0.f, 1.f, 0.f);
|
||||
glVertex3f(0.6f, -0.4f, 0.f);
|
||||
glColor3f(0.f, 0.f, 1.f);
|
||||
glVertex3f(0.f, 0.6f, 0.f);
|
||||
glEnd();
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
//! [code]
|
||||
@@ -0,0 +1,511 @@
|
||||
//========================================================================
|
||||
// This is an example program for the GLFW library
|
||||
//
|
||||
// The program uses a "split window" view, rendering four views of the
|
||||
// same scene in one window (e.g. uesful for 3D modelling software). This
|
||||
// demo uses scissors to separete the four different rendering areas from
|
||||
// each other.
|
||||
//
|
||||
// (If the code seems a little bit strange here and there, it may be
|
||||
// because I am not a friend of orthogonal projections)
|
||||
//========================================================================
|
||||
|
||||
#define GLFW_INCLUDE_GLU
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Global variables
|
||||
//========================================================================
|
||||
|
||||
// Mouse position
|
||||
static double xpos = 0, ypos = 0;
|
||||
|
||||
// Window size
|
||||
static int width, height;
|
||||
|
||||
// Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left,
|
||||
// 4 = lower right
|
||||
static int active_view = 0;
|
||||
|
||||
// Rotation around each axis
|
||||
static int rot_x = 0, rot_y = 0, rot_z = 0;
|
||||
|
||||
// Do redraw?
|
||||
static int do_redraw = 1;
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Draw a solid torus (use a display list for the model)
|
||||
//========================================================================
|
||||
|
||||
#define TORUS_MAJOR 1.5
|
||||
#define TORUS_MINOR 0.5
|
||||
#define TORUS_MAJOR_RES 32
|
||||
#define TORUS_MINOR_RES 32
|
||||
|
||||
static void drawTorus(void)
|
||||
{
|
||||
static GLuint torus_list = 0;
|
||||
int i, j, k;
|
||||
double s, t, x, y, z, nx, ny, nz, scale, twopi;
|
||||
|
||||
if (!torus_list)
|
||||
{
|
||||
// Start recording displaylist
|
||||
torus_list = glGenLists(1);
|
||||
glNewList(torus_list, GL_COMPILE_AND_EXECUTE);
|
||||
|
||||
// Draw torus
|
||||
twopi = 2.0 * M_PI;
|
||||
for (i = 0; i < TORUS_MINOR_RES; i++)
|
||||
{
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (j = 0; j <= TORUS_MAJOR_RES; j++)
|
||||
{
|
||||
for (k = 1; k >= 0; k--)
|
||||
{
|
||||
s = (i + k) % TORUS_MINOR_RES + 0.5;
|
||||
t = j % TORUS_MAJOR_RES;
|
||||
|
||||
// Calculate point on surface
|
||||
x = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * cos(t * twopi / TORUS_MAJOR_RES);
|
||||
y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES);
|
||||
z = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * sin(t * twopi / TORUS_MAJOR_RES);
|
||||
|
||||
// Calculate surface normal
|
||||
nx = x - TORUS_MAJOR * cos(t * twopi / TORUS_MAJOR_RES);
|
||||
ny = y;
|
||||
nz = z - TORUS_MAJOR * sin(t * twopi / TORUS_MAJOR_RES);
|
||||
scale = 1.0 / sqrt(nx*nx + ny*ny + nz*nz);
|
||||
nx *= scale;
|
||||
ny *= scale;
|
||||
nz *= scale;
|
||||
|
||||
glNormal3f((float) nx, (float) ny, (float) nz);
|
||||
glVertex3f((float) x, (float) y, (float) z);
|
||||
}
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// Stop recording displaylist
|
||||
glEndList();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Playback displaylist
|
||||
glCallList(torus_list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Draw the scene (a rotating torus)
|
||||
//========================================================================
|
||||
|
||||
static void drawScene(void)
|
||||
{
|
||||
const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f};
|
||||
const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f};
|
||||
const GLfloat model_shininess = 20.0f;
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
// Rotate the object
|
||||
glRotatef((GLfloat) rot_x * 0.5f, 1.0f, 0.0f, 0.0f);
|
||||
glRotatef((GLfloat) rot_y * 0.5f, 0.0f, 1.0f, 0.0f);
|
||||
glRotatef((GLfloat) rot_z * 0.5f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Set model color (used for orthogonal views, lighting disabled)
|
||||
glColor4fv(model_diffuse);
|
||||
|
||||
// Set model material (used for perspective view, lighting enabled)
|
||||
glMaterialfv(GL_FRONT, GL_DIFFUSE, model_diffuse);
|
||||
glMaterialfv(GL_FRONT, GL_SPECULAR, model_specular);
|
||||
glMaterialf(GL_FRONT, GL_SHININESS, model_shininess);
|
||||
|
||||
// Draw torus
|
||||
drawTorus();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Draw a 2D grid (used for orthogonal views)
|
||||
//========================================================================
|
||||
|
||||
static void drawGrid(float scale, int steps)
|
||||
{
|
||||
int i;
|
||||
float x, y;
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
// Set background to some dark bluish grey
|
||||
glClearColor(0.05f, 0.05f, 0.2f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Setup modelview matrix (flat XY view)
|
||||
glLoadIdentity();
|
||||
gluLookAt(0.0, 0.0, 1.0,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0);
|
||||
|
||||
// We don't want to update the Z-buffer
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
// Set grid color
|
||||
glColor3f(0.0f, 0.5f, 0.5f);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
|
||||
// Horizontal lines
|
||||
x = scale * 0.5f * (float) (steps - 1);
|
||||
y = -scale * 0.5f * (float) (steps - 1);
|
||||
for (i = 0; i < steps; i++)
|
||||
{
|
||||
glVertex3f(-x, y, 0.0f);
|
||||
glVertex3f(x, y, 0.0f);
|
||||
y += scale;
|
||||
}
|
||||
|
||||
// Vertical lines
|
||||
x = -scale * 0.5f * (float) (steps - 1);
|
||||
y = scale * 0.5f * (float) (steps - 1);
|
||||
for (i = 0; i < steps; i++)
|
||||
{
|
||||
glVertex3f(x, -y, 0.0f);
|
||||
glVertex3f(x, y, 0.0f);
|
||||
x += scale;
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
// Enable Z-buffer writing again
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Draw all views
|
||||
//========================================================================
|
||||
|
||||
static void drawAllViews(void)
|
||||
{
|
||||
const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f};
|
||||
const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f};
|
||||
double aspect;
|
||||
|
||||
// Calculate aspect of window
|
||||
if (height > 0)
|
||||
aspect = (double) width / (double) height;
|
||||
else
|
||||
aspect = 1.0;
|
||||
|
||||
// Clear screen
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Enable scissor test
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
// Enable depth test
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
// ** ORTHOGONAL VIEWS **
|
||||
|
||||
// For orthogonal views, use wireframe rendering
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
// Enable line anti-aliasing
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Setup orthogonal projection matrix
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(-3.0 * aspect, 3.0 * aspect, -3.0, 3.0, 1.0, 50.0);
|
||||
|
||||
// Upper left view (TOP VIEW)
|
||||
glViewport(0, height / 2, width / 2, height / 2);
|
||||
glScissor(0, height / 2, width / 2, height / 2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(0.0f, 10.0f, 1e-3f, // Eye-position (above)
|
||||
0.0f, 0.0f, 0.0f, // View-point
|
||||
0.0f, 1.0f, 0.0f); // Up-vector
|
||||
drawGrid(0.5, 12);
|
||||
drawScene();
|
||||
|
||||
// Lower left view (FRONT VIEW)
|
||||
glViewport(0, 0, width / 2, height / 2);
|
||||
glScissor(0, 0, width / 2, height / 2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(0.0f, 0.0f, 10.0f, // Eye-position (in front of)
|
||||
0.0f, 0.0f, 0.0f, // View-point
|
||||
0.0f, 1.0f, 0.0f); // Up-vector
|
||||
drawGrid(0.5, 12);
|
||||
drawScene();
|
||||
|
||||
// Lower right view (SIDE VIEW)
|
||||
glViewport(width / 2, 0, width / 2, height / 2);
|
||||
glScissor(width / 2, 0, width / 2, height / 2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(10.0f, 0.0f, 0.0f, // Eye-position (to the right)
|
||||
0.0f, 0.0f, 0.0f, // View-point
|
||||
0.0f, 1.0f, 0.0f); // Up-vector
|
||||
drawGrid(0.5, 12);
|
||||
drawScene();
|
||||
|
||||
// Disable line anti-aliasing
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
// ** PERSPECTIVE VIEW **
|
||||
|
||||
// For perspective view, use solid rendering
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
// Enable face culling (faster rendering)
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CW);
|
||||
|
||||
// Setup perspective projection matrix
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(65.0f, aspect, 1.0f, 50.0f);
|
||||
|
||||
// Upper right view (PERSPECTIVE VIEW)
|
||||
glViewport(width / 2, height / 2, width / 2, height / 2);
|
||||
glScissor(width / 2, height / 2, width / 2, height / 2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(3.0f, 1.5f, 3.0f, // Eye-position
|
||||
0.0f, 0.0f, 0.0f, // View-point
|
||||
0.0f, 1.0f, 0.0f); // Up-vector
|
||||
|
||||
// Configure and enable light source 1
|
||||
glLightfv(GL_LIGHT1, GL_POSITION, light_position);
|
||||
glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
|
||||
glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
|
||||
glEnable(GL_LIGHT1);
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
// Draw scene
|
||||
drawScene();
|
||||
|
||||
// Disable lighting
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
// Disable face culling
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
// Disable depth test
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Disable scissor test
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
// Draw a border around the active view
|
||||
if (active_view > 0 && active_view != 2)
|
||||
{
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, 2.0, 0.0, 2.0, 0.0, 1.0);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glTranslatef((GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f);
|
||||
|
||||
glColor3f(1.0f, 1.0f, 0.6f);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glVertex2i(0, 0);
|
||||
glVertex2i(1, 0);
|
||||
glVertex2i(1, 1);
|
||||
glVertex2i(0, 1);
|
||||
glVertex2i(0, 0);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Framebuffer size callback function
|
||||
//========================================================================
|
||||
|
||||
static void framebufferSizeFun(GLFWwindow* window, int w, int h)
|
||||
{
|
||||
width = w;
|
||||
height = h > 0 ? h : 1;
|
||||
do_redraw = 1;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Window refresh callback function
|
||||
//========================================================================
|
||||
|
||||
static void windowRefreshFun(GLFWwindow* window)
|
||||
{
|
||||
do_redraw = 1;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Mouse position callback function
|
||||
//========================================================================
|
||||
|
||||
static void cursorPosFun(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
// Depending on which view was selected, rotate around different axes
|
||||
switch (active_view)
|
||||
{
|
||||
case 1:
|
||||
rot_x += (int) (y - ypos);
|
||||
rot_z += (int) (x - xpos);
|
||||
do_redraw = 1;
|
||||
break;
|
||||
case 3:
|
||||
rot_x += (int) (y - ypos);
|
||||
rot_y += (int) (x - xpos);
|
||||
do_redraw = 1;
|
||||
break;
|
||||
case 4:
|
||||
rot_y += (int) (x - xpos);
|
||||
rot_z += (int) (y - ypos);
|
||||
do_redraw = 1;
|
||||
break;
|
||||
default:
|
||||
// Do nothing for perspective view, or if no view is selected
|
||||
break;
|
||||
}
|
||||
|
||||
// Remember cursor position
|
||||
xpos = x;
|
||||
ypos = y;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Mouse button callback function
|
||||
//========================================================================
|
||||
|
||||
static void mouseButtonFun(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
if ((button == GLFW_MOUSE_BUTTON_LEFT) && action == GLFW_PRESS)
|
||||
{
|
||||
// Detect which of the four views was clicked
|
||||
active_view = 1;
|
||||
if (xpos >= width / 2)
|
||||
active_view += 1;
|
||||
if (ypos >= height / 2)
|
||||
active_view += 2;
|
||||
}
|
||||
else if (button == GLFW_MOUSE_BUTTON_LEFT)
|
||||
{
|
||||
// Deselect any previously selected view
|
||||
active_view = 0;
|
||||
}
|
||||
|
||||
do_redraw = 1;
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// main
|
||||
//========================================================================
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GLFWwindow* window;
|
||||
|
||||
// Initialise GLFW
|
||||
if (!glfwInit())
|
||||
{
|
||||
fprintf(stderr, "Failed to initialize GLFW\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Open OpenGL window
|
||||
window = glfwCreateWindow(500, 500, "Split view demo", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
fprintf(stderr, "Failed to open GLFW window\n");
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Set callback functions
|
||||
glfwSetFramebufferSizeCallback(window, framebufferSizeFun);
|
||||
glfwSetWindowRefreshCallback(window, windowRefreshFun);
|
||||
glfwSetCursorPosCallback(window, cursorPosFun);
|
||||
glfwSetMouseButtonCallback(window, mouseButtonFun);
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
// Enable vsync
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
framebufferSizeFun(window, width, height);
|
||||
|
||||
// Main loop
|
||||
for (;;)
|
||||
{
|
||||
// Only redraw if we need to
|
||||
if (do_redraw)
|
||||
{
|
||||
// Draw all views
|
||||
drawAllViews();
|
||||
|
||||
// Swap buffers
|
||||
glfwSwapBuffers(window);
|
||||
|
||||
do_redraw = 0;
|
||||
}
|
||||
|
||||
// Wait for new events
|
||||
glfwWaitEvents();
|
||||
|
||||
// Check if the window should be closed
|
||||
if (glfwWindowShouldClose(window))
|
||||
break;
|
||||
}
|
||||
|
||||
// Close OpenGL window and terminate GLFW
|
||||
glfwTerminate();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
/*****************************************************************************
|
||||
* Wave Simulation in OpenGL
|
||||
* (C) 2002 Jakob Thomsen
|
||||
* http://home.in.tum.de/~thomsen
|
||||
* Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com
|
||||
* Modified for variable frame rate by Marcus Geelnard
|
||||
* 2003-Jan-31: Minor cleanups and speedups / MG
|
||||
* 2010-10-24: Formatting and cleanup - Camilla Berglund
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define GLFW_INCLUDE_GLU
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
|
||||
// Maximum delta T to allow for differential calculations
|
||||
#define MAX_DELTA_T 0.01
|
||||
|
||||
// Animation speed (10.0 looks good)
|
||||
#define ANIMATION_SPEED 10.0
|
||||
|
||||
GLfloat alpha = 210.f, beta = -70.f;
|
||||
GLfloat zoom = 2.f;
|
||||
|
||||
GLboolean locked = GL_FALSE;
|
||||
|
||||
int cursorX;
|
||||
int cursorY;
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
GLfloat x, y, z;
|
||||
GLfloat r, g, b;
|
||||
};
|
||||
|
||||
#define GRIDW 50
|
||||
#define GRIDH 50
|
||||
#define VERTEXNUM (GRIDW*GRIDH)
|
||||
|
||||
#define QUADW (GRIDW - 1)
|
||||
#define QUADH (GRIDH - 1)
|
||||
#define QUADNUM (QUADW*QUADH)
|
||||
|
||||
GLuint quad[4 * QUADNUM];
|
||||
struct Vertex vertex[VERTEXNUM];
|
||||
|
||||
/* The grid will look like this:
|
||||
*
|
||||
* 3 4 5
|
||||
* *---*---*
|
||||
* | | |
|
||||
* | 0 | 1 |
|
||||
* | | |
|
||||
* *---*---*
|
||||
* 0 1 2
|
||||
*/
|
||||
|
||||
//========================================================================
|
||||
// Initialize grid geometry
|
||||
//========================================================================
|
||||
|
||||
void init_vertices(void)
|
||||
{
|
||||
int x, y, p;
|
||||
|
||||
// Place the vertices in a grid
|
||||
for (y = 0; y < GRIDH; y++)
|
||||
{
|
||||
for (x = 0; x < GRIDW; x++)
|
||||
{
|
||||
p = y * GRIDW + x;
|
||||
|
||||
vertex[p].x = (GLfloat) (x - GRIDW / 2) / (GLfloat) (GRIDW / 2);
|
||||
vertex[p].y = (GLfloat) (y - GRIDH / 2) / (GLfloat) (GRIDH / 2);
|
||||
vertex[p].z = 0;
|
||||
|
||||
if ((x % 4 < 2) ^ (y % 4 < 2))
|
||||
vertex[p].r = 0.0;
|
||||
else
|
||||
vertex[p].r = 1.0;
|
||||
|
||||
vertex[p].g = (GLfloat) y / (GLfloat) GRIDH;
|
||||
vertex[p].b = 1.f - ((GLfloat) x / (GLfloat) GRIDW + (GLfloat) y / (GLfloat) GRIDH) / 2.f;
|
||||
}
|
||||
}
|
||||
|
||||
for (y = 0; y < QUADH; y++)
|
||||
{
|
||||
for (x = 0; x < QUADW; x++)
|
||||
{
|
||||
p = 4 * (y * QUADW + x);
|
||||
|
||||
quad[p + 0] = y * GRIDW + x; // Some point
|
||||
quad[p + 1] = y * GRIDW + x + 1; // Neighbor at the right side
|
||||
quad[p + 2] = (y + 1) * GRIDW + x + 1; // Upper right neighbor
|
||||
quad[p + 3] = (y + 1) * GRIDW + x; // Upper neighbor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double dt;
|
||||
double p[GRIDW][GRIDH];
|
||||
double vx[GRIDW][GRIDH], vy[GRIDW][GRIDH];
|
||||
double ax[GRIDW][GRIDH], ay[GRIDW][GRIDH];
|
||||
|
||||
//========================================================================
|
||||
// Initialize grid
|
||||
//========================================================================
|
||||
|
||||
void init_grid(void)
|
||||
{
|
||||
int x, y;
|
||||
double dx, dy, d;
|
||||
|
||||
for (y = 0; y < GRIDH; y++)
|
||||
{
|
||||
for (x = 0; x < GRIDW; x++)
|
||||
{
|
||||
dx = (double) (x - GRIDW / 2);
|
||||
dy = (double) (y - GRIDH / 2);
|
||||
d = sqrt(dx * dx + dy * dy);
|
||||
if (d < 0.1 * (double) (GRIDW / 2))
|
||||
{
|
||||
d = d * 10.0;
|
||||
p[x][y] = -cos(d * (M_PI / (double)(GRIDW * 4))) * 100.0;
|
||||
}
|
||||
else
|
||||
p[x][y] = 0.0;
|
||||
|
||||
vx[x][y] = 0.0;
|
||||
vy[x][y] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Draw scene
|
||||
//========================================================================
|
||||
|
||||
void draw_scene(GLFWwindow* window)
|
||||
{
|
||||
// Clear the color and depth buffers
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// We don't want to modify the projection matrix
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// Move back
|
||||
glTranslatef(0.0, 0.0, -zoom);
|
||||
// Rotate the view
|
||||
glRotatef(beta, 1.0, 0.0, 0.0);
|
||||
glRotatef(alpha, 0.0, 0.0, 1.0);
|
||||
|
||||
glDrawElements(GL_QUADS, 4 * QUADNUM, GL_UNSIGNED_INT, quad);
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Initialize Miscellaneous OpenGL state
|
||||
//========================================================================
|
||||
|
||||
void init_opengl(void)
|
||||
{
|
||||
// Use Gouraud (smooth) shading
|
||||
glShadeModel(GL_SMOOTH);
|
||||
|
||||
// Switch on the z-buffer
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(struct Vertex), vertex);
|
||||
glColorPointer(3, GL_FLOAT, sizeof(struct Vertex), &vertex[0].r); // Pointer to the first color
|
||||
|
||||
glPointSize(2.0);
|
||||
|
||||
// Background color is black
|
||||
glClearColor(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Modify the height of each vertex according to the pressure
|
||||
//========================================================================
|
||||
|
||||
void adjust_grid(void)
|
||||
{
|
||||
int pos;
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y < GRIDH; y++)
|
||||
{
|
||||
for (x = 0; x < GRIDW; x++)
|
||||
{
|
||||
pos = y * GRIDW + x;
|
||||
vertex[pos].z = (float) (p[x][y] * (1.0 / 50.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Calculate wave propagation
|
||||
//========================================================================
|
||||
|
||||
void calc_grid(void)
|
||||
{
|
||||
int x, y, x2, y2;
|
||||
double time_step = dt * ANIMATION_SPEED;
|
||||
|
||||
// Compute accelerations
|
||||
for (x = 0; x < GRIDW; x++)
|
||||
{
|
||||
x2 = (x + 1) % GRIDW;
|
||||
for(y = 0; y < GRIDH; y++)
|
||||
ax[x][y] = p[x][y] - p[x2][y];
|
||||
}
|
||||
|
||||
for (y = 0; y < GRIDH; y++)
|
||||
{
|
||||
y2 = (y + 1) % GRIDH;
|
||||
for(x = 0; x < GRIDW; x++)
|
||||
ay[x][y] = p[x][y] - p[x][y2];
|
||||
}
|
||||
|
||||
// Compute speeds
|
||||
for (x = 0; x < GRIDW; x++)
|
||||
{
|
||||
for (y = 0; y < GRIDH; y++)
|
||||
{
|
||||
vx[x][y] = vx[x][y] + ax[x][y] * time_step;
|
||||
vy[x][y] = vy[x][y] + ay[x][y] * time_step;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute pressure
|
||||
for (x = 1; x < GRIDW; x++)
|
||||
{
|
||||
x2 = x - 1;
|
||||
for (y = 1; y < GRIDH; y++)
|
||||
{
|
||||
y2 = y - 1;
|
||||
p[x][y] = p[x][y] + (vx[x2][y] - vx[x][y] + vy[x][y2] - vy[x][y]) * time_step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Print errors
|
||||
//========================================================================
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Handle key strokes
|
||||
//========================================================================
|
||||
|
||||
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (action != GLFW_PRESS)
|
||||
return;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
break;
|
||||
case GLFW_KEY_SPACE:
|
||||
init_grid();
|
||||
break;
|
||||
case GLFW_KEY_LEFT:
|
||||
alpha += 5;
|
||||
break;
|
||||
case GLFW_KEY_RIGHT:
|
||||
alpha -= 5;
|
||||
break;
|
||||
case GLFW_KEY_UP:
|
||||
beta -= 5;
|
||||
break;
|
||||
case GLFW_KEY_DOWN:
|
||||
beta += 5;
|
||||
break;
|
||||
case GLFW_KEY_PAGE_UP:
|
||||
zoom -= 0.25f;
|
||||
if (zoom < 0.f)
|
||||
zoom = 0.f;
|
||||
break;
|
||||
case GLFW_KEY_PAGE_DOWN:
|
||||
zoom += 0.25f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Callback function for mouse button events
|
||||
//========================================================================
|
||||
|
||||
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
if (button != GLFW_MOUSE_BUTTON_LEFT)
|
||||
return;
|
||||
|
||||
if (action == GLFW_PRESS)
|
||||
{
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
locked = GL_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
locked = GL_FALSE;
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Callback function for cursor motion events
|
||||
//========================================================================
|
||||
|
||||
void cursor_position_callback(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
if (locked)
|
||||
{
|
||||
alpha += (GLfloat) (x - cursorX) / 10.f;
|
||||
beta += (GLfloat) (y - cursorY) / 10.f;
|
||||
}
|
||||
|
||||
cursorX = (int) x;
|
||||
cursorY = (int) y;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Callback function for scroll events
|
||||
//========================================================================
|
||||
|
||||
void scroll_callback(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
zoom += (float) y / 4.f;
|
||||
if (zoom < 0)
|
||||
zoom = 0;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Callback function for framebuffer resize events
|
||||
//========================================================================
|
||||
|
||||
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
float ratio = 1.f;
|
||||
|
||||
if (height > 0)
|
||||
ratio = (float) width / (float) height;
|
||||
|
||||
// Setup viewport
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
// Change to the projection matrix and set our viewing volume
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(60.0, ratio, 1.0, 1024.0);
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// main
|
||||
//========================================================================
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
GLFWwindow* window;
|
||||
double t, dt_total, t_old;
|
||||
int width, height;
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
window = glfwCreateWindow(640, 480, "Wave Simulation", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||||
glfwSetScrollCallback(window, scroll_callback);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
framebuffer_size_callback(window, width, height);
|
||||
|
||||
// Initialize OpenGL
|
||||
init_opengl();
|
||||
|
||||
// Initialize simulation
|
||||
init_vertices();
|
||||
init_grid();
|
||||
adjust_grid();
|
||||
|
||||
// Initialize timer
|
||||
t_old = glfwGetTime() - 0.01;
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
t = glfwGetTime();
|
||||
dt_total = t - t_old;
|
||||
t_old = t;
|
||||
|
||||
// Safety - iterate if dt_total is too large
|
||||
while (dt_total > 0.f)
|
||||
{
|
||||
// Select iteration time step
|
||||
dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total;
|
||||
dt_total -= dt;
|
||||
|
||||
// Calculate wave propagation
|
||||
calc_grid();
|
||||
}
|
||||
|
||||
// Compute height of each vertex
|
||||
adjust_grid();
|
||||
|
||||
// Draw wave grid to OpenGL display
|
||||
draw_scene(window);
|
||||
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user