view glxdragon.cpp @ 1:4727156927ea

One must use g++ for C++ code, otherwise libstdc++ won't get linked in.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 27 Oct 2019 17:19:47 +0200
parents 3d74a9dd96e4
children b45d8958e5a6
line wrap: on
line source


// Copyright (c) 2009, Thomas Trummer
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the <organization> nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY Thomas Trummer ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


#include <SDL.h>
#include <SDL_opengl.h>

#include <iostream>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <ctime>


struct Mesh
{
	std::vector<float>		vertices;
	std::vector<unsigned>	faces;
}
dragonMesh;


void init(const int windowWidth, const int windowHeight, const std::string& windowTitle)
{
	std::stringstream ss;


	if (SDL_Init(SDL_INIT_VIDEO) != 0)
	{
		ss << "Unable to initialize SDL: " << SDL_GetError() << '\n';

		throw std::runtime_error(ss.str());
	}


	SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    8);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  24);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);


	SDL_WM_SetCaption(windowTitle.c_str(), 0);


	if ((SDL_SetVideoMode(windowWidth, windowHeight, 0, SDL_OPENGL)) == NULL)
	{
		ss << "Couldn't set GL mode: " << SDL_GetError() << '\n';

		throw std::runtime_error(ss.str());
	}


	std::cout << "GL_VENDOR   : " << glGetString(GL_VENDOR)   << std::endl;
	std::cout << "GL_RENDERER : " << glGetString(GL_RENDERER) << std::endl;
	std::cout << "GL_VERSION  : " << glGetString(GL_VERSION)  << std::endl;

	std::cout << std::endl;


	// Setup the window and view port
	glViewport(0, 0, windowWidth, windowHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(45.0f, GLfloat(windowWidth) / GLfloat(windowHeight), 0.1f, 1000.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();


	// Enable back face culling
	glEnable(GL_CULL_FACE);

    // Enable smooth shading
    glShadeModel(GL_SMOOTH);

    // Enable the depth buffer
    glEnable(GL_DEPTH_TEST);

    // Setup depth buffer
    glClearDepth(1.0f);

    // Set the depth buffer function
    glDepthFunc(GL_LEQUAL);

    // Enable vertex and and normal arrays
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    // Set correct perspective correction
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}


void initScene()
{
    glEnable(GL_COLOR_MATERIAL);

    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    glMateriali(GL_FRONT, GL_SHININESS, 96);

    float specReflection[] = { 0.8f, 0.8f, 0.8f, 1.0f };
    glMaterialfv(GL_FRONT, GL_SPECULAR, specReflection);


    glEnable(GL_LIGHT0);

    // Define the light components and position
    GLfloat ambient [] = {  0.2f,  0.2f, 0.2f, 1.0f };
    GLfloat diffuse [] = {  0.8f,  0.8f, 0.8f, 1.0f };
    GLfloat specular[] = {  0.5f,  0.5f, 0.5f, 1.0f };
    GLfloat position[] = { 10.0f, 10.0f, 0.0f, 0.0f };

    // Define the light components and position
    glLightfv(GL_LIGHT0, GL_AMBIENT,  ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
    glLightfv(GL_LIGHT0, GL_POSITION, position);

    // Define the camera
    gluLookAt(0, 0.12, 0.24, 0, 0.12, 0, 0, 1, 0);
}


void done()
{
	SDL_Quit();
}


void drawModelVA(const Mesh& mesh)
{
    int maxIndices;

	glGetIntegerv(GL_MAX_ELEMENTS_INDICES,  &maxIndices);


	glVertexPointer(3, GL_FLOAT, 24, &mesh.vertices[0]);
    glNormalPointer(   GL_FLOAT, 24, &mesh.vertices[3]);


	for(size_t n = 0; n < mesh.faces.size() / 3; n += maxIndices)
	{
		const int count = std::min(maxIndices, int(mesh.faces.size() / 3 - n));

		glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &dragonMesh.faces[n * 3]);
	}
}


bool paintGL()
{
    glClear(GL_DEPTH_BUFFER_BIT);


	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();

	glOrtho(0.0, 1.0, 0.0, 1.0, -1, 1);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();


    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);

    // Draw the background gradient
  	glBegin(GL_QUADS);
	{
		glColor3ub(0x3B, 0x3B, 0x75);
		glVertex2f(0.0f, 0.0f);
		glVertex2f(1.0f, 0.0f);

		glColor3ub(0x00, 0x00, 0x00);
		glVertex2f(1.0f, 1.0f);
		glVertex2f(0.0f, 1.0f);
	}
	glEnd();


	// Restore the 3D projection
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();


    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);


    // Set the color of the model
    glColor3ub(0x90, 0x80, 0x90);

    // Draw the model using vertex arrays
    drawModelVA(dragonMesh);

    // Draw the current frame
    SDL_GL_SwapBuffers();



    static int steps = 0;

    // Rotate for 2 degrees
    glRotatef(2.0f, 0, 1, 0);

    // Return true if a full rotation was done
    return (steps++ == 180) ? (steps = 0, true) : false;
}


void runEventLoop()
{
	static std::clock_t startTime = std::clock();

	while (true)
	{
		SDL_Event event;

		if (SDL_PollEvent(&event))
		{
			if (event.type == SDL_QUIT)
				break;
		}
		else
		{
			// Render the next frame and test if a full turn was completed
			if (paintGL())
			{
				// Get the time it took to render a full turn
				double time = double(std::clock() - startTime) / CLOCKS_PER_SEC;

				// Print the current frames per second
				std::printf("%.1lf seconds for 180 frames = %.1lf FPS\n", time, 180 / time);

				// Restart the timer
				startTime = std::clock();
			}
		}
	}
}


void loadMesh(const std::string& fileName, Mesh& mesh)
{
	std::ifstream in(fileName.c_str(), std::ios::binary);


	if (!in.is_open())
	{
		std::stringstream ss;

		ss << "Unable to open file: " << fileName << '\n';

		throw std::runtime_error(ss.str());

	}


	mesh.vertices.resize(100139 * 6);

	in.read(reinterpret_cast<char*>(&mesh.vertices[0]), 100139 * 6 * 4);


	mesh.faces.resize(200198 * 3);


	for(unsigned i = 0; i < 200198; i++)
	{
		in.seekg(1, std::ios::cur);

		in.read(reinterpret_cast<char*>(&mesh.faces[i*3]), 3 * 4);
	}
}


int main()
{
	try
	{
		loadMesh("dragon.mesh", dragonMesh);

		init(640, 480, "glxdragon");

		initScene();

		runEventLoop();
	}
	catch(std::runtime_error& e)
	{
		std::cerr << e.what();
	}

	done();
}