mirror of
https://github.com/mapmapteam/mapmap.git
synced 2026-04-01 04:59:45 +02:00
371 lines
8.0 KiB
C
371 lines
8.0 KiB
C
#include "SDL.h"
|
|
#include "SDL_opengl.h"
|
|
#include "SDL_image.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#define WIDTH 640
|
|
#define HEIGHT 480
|
|
|
|
static const char * IMAGE_FILE = "example.png";
|
|
|
|
GLfloat yaw;
|
|
GLfloat pitch;
|
|
int level;
|
|
|
|
static void
|
|
subdivide (GLfloat point0[3], GLfloat point1[3], GLfloat point2[3], int level)
|
|
{
|
|
int coord;
|
|
GLfloat midpoint[3][3];
|
|
|
|
/* Don't subdivide any further; just draw the triangle */
|
|
if (level==0)
|
|
{
|
|
glColor3fv (point0);
|
|
glVertex3fv (point0);
|
|
glColor3fv (point1);
|
|
glVertex3fv (point1);
|
|
glColor3fv (point2);
|
|
glVertex3fv (point2);
|
|
return;
|
|
}
|
|
|
|
/* Calculate a midpoint on each edge of the triangle */
|
|
for (coord = 0; coord<3; coord++)
|
|
{
|
|
midpoint[0][coord] = (point0[coord] + point1[coord])*0.5;
|
|
midpoint[1][coord] = (point1[coord] + point2[coord])*0.5;
|
|
midpoint[2][coord] = (point2[coord] + point0[coord])*0.5;
|
|
}
|
|
|
|
/* Subdivide each triangle into three more */ /* . */
|
|
level--; /* /X\ */
|
|
subdivide (point0,midpoint[0],midpoint[2],level); /* /xxx\ */
|
|
subdivide (point1,midpoint[1],midpoint[0],level); /* /X\ /X\ */
|
|
subdivide (point2,midpoint[2],midpoint[1],level); /* /XXXVXXX\ */
|
|
}
|
|
|
|
static void
|
|
paint_triangles ()
|
|
{
|
|
int i;
|
|
|
|
/* Coordinates of the 6 vertices of the octahedron */
|
|
static GLfloat point[6][3] = {
|
|
{1.0f,0.0f,0.0f},{-1.0f,0.0f,0.0f},
|
|
{0.0f,1.0f,0.0f},{0.0f,-1.0f,0.0f},
|
|
{0.0f,0.0f,1.0f},{0.0f,0.0f,-1.0f}
|
|
};
|
|
|
|
/* indices of the vertices of the triangles which make up each of
|
|
* the 8 faces of the octahedron */
|
|
static int triangle[8][3] = {
|
|
{2,4,0},{2,0,5},{2,5,1},{2,1,4},{3,0,4},{3,5,0},{3,1,5},{3,4,1}
|
|
};
|
|
|
|
/* Rotate the object */
|
|
glRotatef (pitch, 1.0f, 0.0f, 0.0f);
|
|
glRotatef (yaw, 0.0f, 1.0f, 0.0f);
|
|
|
|
/* Draw the triangles which make up the object */
|
|
glBegin (GL_TRIANGLES);
|
|
|
|
for (i=0; i<8; i++)
|
|
{
|
|
subdivide (point[triangle[i][0]],point[triangle[i][1]],point[triangle[i][2]],level);
|
|
}
|
|
|
|
glEnd ();
|
|
|
|
/* increment the rotation every frame */
|
|
yaw = yaw + 0.05;
|
|
}
|
|
|
|
static void
|
|
paint_begin ()
|
|
{
|
|
/* Clear the color plane and the z-buffer */
|
|
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glLoadIdentity ();
|
|
|
|
/* Move the object 2 units away from the camera */
|
|
glTranslatef (0.0f, 0.0f, -2.0f);
|
|
}
|
|
|
|
|
|
static void
|
|
paint_end ()
|
|
{
|
|
/* finally, swap the back and front buffers */
|
|
SDL_GL_SwapBuffers ();
|
|
}
|
|
|
|
static void
|
|
setup_sdl ()
|
|
{
|
|
const SDL_VideoInfo* video;
|
|
int img_flags;
|
|
int img_initted;
|
|
|
|
if (SDL_Init (SDL_INIT_VIDEO) < 0 )
|
|
{
|
|
fprintf (stderr, "Couldn't initialize SDL: %s\n", SDL_GetError ());
|
|
exit (1);
|
|
}
|
|
|
|
/* Quit SDL properly on exit */
|
|
atexit (SDL_Quit);
|
|
|
|
/* Get the current video information */
|
|
video = SDL_GetVideoInfo ( );
|
|
if ( video == NULL )
|
|
{
|
|
fprintf (stderr, "Couldn't get video information: %s\n", SDL_GetError ());
|
|
exit (1);
|
|
}
|
|
|
|
/* Set the minimum requirements for the OpenGL window */
|
|
SDL_GL_SetAttribute ( SDL_GL_RED_SIZE, 5 );
|
|
SDL_GL_SetAttribute ( SDL_GL_GREEN_SIZE, 5 );
|
|
SDL_GL_SetAttribute ( SDL_GL_BLUE_SIZE, 5 );
|
|
SDL_GL_SetAttribute ( SDL_GL_DEPTH_SIZE, 16 );
|
|
SDL_GL_SetAttribute ( SDL_GL_DOUBLEBUFFER, 1 );
|
|
|
|
/* Note the SDL_DOUBLEBUF flag is not required to enable double
|
|
* buffering when setting an OpenGL video mode.
|
|
* Double buffering is enabled or disabled using the
|
|
* SDL_GL_DOUBLEBUFFER attribute.
|
|
*/
|
|
if ( SDL_SetVideoMode ( WIDTH, HEIGHT, video->vfmt->BitsPerPixel, SDL_OPENGL ) == 0 )
|
|
{
|
|
fprintf (stderr, "Couldn't set video mode: %s\n", SDL_GetError ());
|
|
exit (1);
|
|
}
|
|
|
|
img_flags = IMG_INIT_JPG | IMG_INIT_PNG;
|
|
img_initted = IMG_Init (img_flags);
|
|
if (img_initted & img_flags != img_flags)
|
|
{
|
|
printf ("IMG_Init: Failed to init required jpg and png support!\n");
|
|
printf ("IMG_Init: %s\n", IMG_GetError ());
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
setup_opengl ()
|
|
{
|
|
float aspect = (float)WIDTH / (float)HEIGHT;
|
|
|
|
/* Make the viewport cover the whole window */
|
|
glViewport (0, 0, WIDTH, HEIGHT);
|
|
|
|
/* Set the camera projection matrix:
|
|
* field of view: 90 degrees
|
|
* near clipping plane at 0.1
|
|
* far clipping plane at 100.0
|
|
*/
|
|
glMatrixMode (GL_PROJECTION);
|
|
glLoadIdentity ();
|
|
|
|
gluPerspective (60.0, aspect, 0.1, 100.0);
|
|
/* We're done with the camera, now matrix operations
|
|
* will affect the modelview matrix
|
|
* */
|
|
glMatrixMode (GL_MODELVIEW);
|
|
|
|
/* set the clear color to gray */
|
|
glClearColor (0.5, 0.5 ,0.5, 0);
|
|
|
|
/* We want z-buffer tests enabled*/
|
|
glEnable (GL_DEPTH_TEST);
|
|
|
|
/* Do draw back-facing polygons*/
|
|
glDisable (GL_CULL_FACE);
|
|
}
|
|
|
|
static void
|
|
EnableTransparency ()
|
|
{
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
static GLuint
|
|
LoadTexture(const char *filename, int *textw, int *texth)
|
|
{
|
|
SDL_Surface *surface;
|
|
GLuint textureid;
|
|
int mode;
|
|
|
|
surface = IMG_Load (filename);
|
|
|
|
// Or if you don't use SDL_image you can use SDL_LoadBMP here instead:
|
|
// surface = SDL_LoadBMP(filename);
|
|
|
|
// could not load filename
|
|
if (! surface)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// work out what format to tell glTexImage2D to use...
|
|
if (surface->format->BytesPerPixel == 3)
|
|
{ // RGB 24bit
|
|
mode = GL_RGB;
|
|
}
|
|
else if (surface->format->BytesPerPixel == 4)
|
|
{ // RGBA 32bit
|
|
mode = GL_RGBA;
|
|
}
|
|
else
|
|
{
|
|
SDL_FreeSurface (surface);
|
|
return 0;
|
|
}
|
|
|
|
*textw = surface->w;
|
|
*texth = surface->h;
|
|
// create one texture name
|
|
glGenTextures (1, &textureid);
|
|
|
|
// tell opengl to use the generated texture name
|
|
glBindTexture (GL_TEXTURE_2D, textureid);
|
|
|
|
// this reads from the sdl surface and puts it into an opengl texture
|
|
glTexImage2D (GL_TEXTURE_2D, 0, mode, surface->w, surface->h, 0, mode, GL_UNSIGNED_BYTE, surface->pixels);
|
|
|
|
// these affect how this texture is drawn later on...
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
// clean up
|
|
SDL_FreeSurface (surface);
|
|
|
|
printf ("Loaded image %s %dx%d\n", filename, *textw, *texth);
|
|
|
|
return textureid;
|
|
}
|
|
|
|
static void
|
|
DrawTexture(int x, int y, GLuint textureid, int textw, int texth)
|
|
{
|
|
// tell opengl to use the generated texture name
|
|
glBindTexture (GL_TEXTURE_2D, textureid);
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
// make a rectangle
|
|
glBegin (GL_QUADS);
|
|
|
|
// top left
|
|
glTexCoord2i (0, 0);
|
|
glVertex3f (x, y, 0);
|
|
|
|
// top right
|
|
glTexCoord2i (1, 0);
|
|
glVertex3f (x + textw, y, 0);
|
|
|
|
// bottom right
|
|
glTexCoord2i (1, 1);
|
|
glVertex3f (x + textw, y + texth, 0);
|
|
|
|
// bottom left
|
|
glTexCoord2i (0, 1);
|
|
glVertex3f (x, y + texth, 0);
|
|
|
|
glEnd ();
|
|
|
|
glDisable (GL_TEXTURE_2D );
|
|
}
|
|
|
|
static void
|
|
main_loop ()
|
|
{
|
|
SDL_Event event;
|
|
|
|
GLuint texture;
|
|
int textw, texth;
|
|
|
|
printf ("Loading texture %s\n", IMAGE_FILE);
|
|
texture = LoadTexture (IMAGE_FILE, &textw, &texth);
|
|
|
|
while (1)
|
|
{
|
|
/* process pending events */
|
|
while (SDL_PollEvent (&event))
|
|
{
|
|
switch (event.type)
|
|
{
|
|
case SDL_KEYDOWN:
|
|
switch (event.key.keysym.sym)
|
|
{
|
|
case SDLK_ESCAPE:
|
|
exit (0);
|
|
break;
|
|
|
|
case SDLK_KP_PLUS:
|
|
level++;
|
|
if (level > 5)
|
|
level=5;
|
|
break;
|
|
|
|
case SDLK_KP_MINUS:
|
|
level--;
|
|
if (level < 0)
|
|
level=0;
|
|
break;
|
|
|
|
default:
|
|
//no default key processing
|
|
// (stops compiler warnings for unhandled SDL keydefs
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEMOTION:
|
|
pitch += event.motion.yrel;
|
|
if (pitch < -70)
|
|
pitch = -70;
|
|
if (pitch > 70)
|
|
pitch = 70;
|
|
break;
|
|
|
|
case SDL_QUIT:
|
|
exit (0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* update the screen */
|
|
paint_begin ();
|
|
paint_triangles ();
|
|
glColor3f (1.0, 1.0, 1.0);
|
|
DrawTexture (0, 0, texture, textw, texth);
|
|
paint_end ();
|
|
|
|
/* Wait 50ms to avoid using up all the CPU time */
|
|
SDL_Delay (50);
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
main (int argc, char* argv[])
|
|
{
|
|
setup_sdl ();
|
|
|
|
setup_opengl ();
|
|
|
|
yaw = 45;
|
|
pitch = 0;
|
|
level = 2;
|
|
|
|
main_loop ();
|
|
|
|
return 0;
|
|
}
|