/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsiteс.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #include "app/system.h" #include "common/config.h" #include "common/logger.h" #include "common/image.h" #include "graphics/engine/modelfile.h" #include "graphics/opengl/gldevice.h" #include "math/geometry.h" #include #include #include #include #include enum KeySlots { K_RotXUp, K_RotXDown, K_RotYLeft, K_RotYRight, K_Forward, K_Back, K_Left, K_Right, K_Up, K_Down, K_Count }; bool KEYMAP[K_Count] = { false }; Math::Vector TRANSLATION(0.0f, 0.0f, 30.0f); Math::Vector ROTATION; const int FRAME_DELAY = 5000; std::map TEXS; SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL; Gfx::Texture GetTexture(const std::string &name) { std::map::iterator it = TEXS.find(name); if (it == TEXS.end()) return Gfx::Texture(); return (*it).second; } void LoadTexture(Gfx::CGLDevice *device, const std::string &name) { if (name.empty()) return; Gfx::Texture tex = GetTexture(name); if (tex.Valid()) return; CImage img; if (! img.Load(std::string("tex/") + name)) { std::string err = img.GetError(); GetLogger()->Error("Texture not loaded, error: %s!\n", err.c_str()); } else { Gfx::TextureCreateParams texCreateParams; texCreateParams.mipmap = true; texCreateParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR; texCreateParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR; tex = device->CreateTexture(&img, texCreateParams); } TEXS[name] = tex; } void Init(Gfx::CGLDevice *device, Gfx::CModelFile *model) { const std::vector &triangles = model->GetTriangles(); for (int i = 0; i < static_cast( triangles.size() ); ++i) { LoadTexture(device, triangles[i].tex1Name); LoadTexture(device, triangles[i].tex2Name); } device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true); device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true); device->SetShadeModel(Gfx::SHADE_SMOOTH); Gfx::Light light; light.type = Gfx::LIGHT_DIRECTIONAL; light.ambient = Gfx::Color(0.4f, 0.4f, 0.4f, 0.0f); light.diffuse = Gfx::Color(0.8f, 0.8f, 0.8f, 0.0f); light.specular = Gfx::Color(0.2f, 0.2f, 0.2f, 0.0f); light.position = Math::Vector(0.0f, 0.0f, -1.0f); light.direction = Math::Vector(0.0f, 0.0f, 1.0f); device->SetGlobalAmbient(Gfx::Color(0.5f, 0.5f, 0.5f, 0.0f)); device->SetLight(0, light); device->SetLightEnabled(0, true); } void Render(Gfx::CGLDevice *device, Gfx::CModelFile *modelFile) { device->BeginScene(); Math::Matrix persp; Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f); device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp); Math::Matrix id; id.LoadIdentity(); device->SetTransform(Gfx::TRANSFORM_WORLD, id); Math::Matrix viewMat; Math::LoadTranslationMatrix(viewMat, TRANSLATION); Math::Matrix rot; Math::LoadRotationXZYMatrix(rot, ROTATION); viewMat = Math::MultiplyMatrices(viewMat, rot); device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat); const std::vector &triangles = modelFile->GetTriangles(); Gfx::VertexTex2 tri[3]; for (int i = 0; i < static_cast( triangles.size() ); ++i) { device->SetTexture(0, GetTexture(triangles[i].tex1Name)); device->SetTexture(1, GetTexture(triangles[i].tex2Name)); device->SetTextureEnabled(0, true); device->SetTextureEnabled(1, true); device->SetMaterial(triangles[i].material); tri[0] = triangles[i].p1; tri[1] = triangles[i].p2; tri[2] = triangles[i].p3; device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, tri, 3); } device->EndScene(); } void Update() { const float ROT_SPEED = 80.0f * Math::DEG_TO_RAD; // rad / sec const float TRANS_SPEED = 3.0f; // units / sec GetSystemUtils()->GetCurrentTimeStamp(CURR_TIME); float timeDiff = GetSystemUtils()->TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC); GetSystemUtils()->CopyTimeStamp(PREV_TIME, CURR_TIME); if (KEYMAP[K_RotYLeft]) ROTATION.y -= ROT_SPEED * timeDiff; if (KEYMAP[K_RotYRight]) ROTATION.y += ROT_SPEED * timeDiff; if (KEYMAP[K_RotXDown]) ROTATION.x -= ROT_SPEED * timeDiff; if (KEYMAP[K_RotXUp]) ROTATION.x += ROT_SPEED * timeDiff; if (KEYMAP[K_Forward]) TRANSLATION.z -= TRANS_SPEED * timeDiff; if (KEYMAP[K_Back]) TRANSLATION.z += TRANS_SPEED * timeDiff; if (KEYMAP[K_Left]) TRANSLATION.x += TRANS_SPEED * timeDiff; if (KEYMAP[K_Right]) TRANSLATION.x -= TRANS_SPEED * timeDiff; if (KEYMAP[K_Up]) TRANSLATION.y += TRANS_SPEED * timeDiff; if (KEYMAP[K_Down]) TRANSLATION.y -= TRANS_SPEED * timeDiff; } void KeyboardDown(SDLKey key) { switch (key) { case SDLK_LEFT: KEYMAP[K_RotYLeft] = true; break; case SDLK_RIGHT: KEYMAP[K_RotYRight] = true; break; case SDLK_UP: KEYMAP[K_RotXUp] = true; break; case SDLK_DOWN: KEYMAP[K_RotXDown] = true; break; case SDLK_w: KEYMAP[K_Forward] = true; break; case SDLK_s: KEYMAP[K_Back] = true; break; case SDLK_a: KEYMAP[K_Left] = true; break; case SDLK_d: KEYMAP[K_Right] = true; break; case SDLK_z: KEYMAP[K_Down] = true; break; case SDLK_x: KEYMAP[K_Up] = true; break; default: break; } } void KeyboardUp(SDLKey key) { switch (key) { case SDLK_LEFT: KEYMAP[K_RotYLeft] = false; break; case SDLK_RIGHT: KEYMAP[K_RotYRight] = false; break; case SDLK_UP: KEYMAP[K_RotXUp] = false; break; case SDLK_DOWN: KEYMAP[K_RotXDown] = false; break; case SDLK_w: KEYMAP[K_Forward] = false; break; case SDLK_s: KEYMAP[K_Back] = false; break; case SDLK_a: KEYMAP[K_Left] = false; break; case SDLK_d: KEYMAP[K_Right] = false; break; case SDLK_z: KEYMAP[K_Down] = false; break; case SDLK_x: KEYMAP[K_Up] = false; break; default: break; } } extern "C" { int SDL_MAIN_FUNC(int argc, char *argv[]) { CLogger logger; CSystemUtils* systemUtils = CSystemUtils::Create(); // platform-specific utils systemUtils->Init(); PREV_TIME = GetSystemUtils()->CreateTimeStamp(); CURR_TIME = GetSystemUtils()->CreateTimeStamp(); GetSystemUtils()->GetCurrentTimeStamp(PREV_TIME); GetSystemUtils()->GetCurrentTimeStamp(CURR_TIME); if (argc != 3) { std::cerr << "Usage: " << argv[0] << " {old|new_txt|new_bin} model_file" << std::endl; return 1; } Gfx::CModelFile *modelFile = new Gfx::CModelFile(); if (std::string(argv[1]) == "old") { if (! modelFile->ReadModel(argv[2])) { std::cerr << "Error reading model file" << std::endl; return 1; } } else if (std::string(argv[1]) == "new_txt") { if (! modelFile->ReadTextModel(argv[2])) { std::cerr << "Error reading model file" << std::endl; return 1; } } else if (std::string(argv[1]) == "new_bin") { if (! modelFile->ReadBinaryModel(argv[2])) { std::cerr << "Error reading model file" << std::endl; return 1; } } else { std::cerr << "Usage: " << argv[0] << "{old|new_txt|new_bin} model_file" << std::endl; return 1; } // Without any error checking, for simplicity SDL_Init(SDL_INIT_VIDEO); IMG_Init(IMG_INIT_PNG); const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; if (videoInfo->hw_available) videoFlags |= SDL_HWSURFACE; else videoFlags |= SDL_SWSURFACE; if (videoInfo->blit_hw) videoFlags |= SDL_HWACCEL; 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_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags); SDL_WM_SetCaption("Model Test", "Model Test"); Gfx::CGLDevice *device = new Gfx::CGLDevice(Gfx::GLDeviceConfig()); device->Create(); Init(device, modelFile); bool done = false; while (! done) { Render(device, modelFile); Update(); SDL_GL_SwapBuffers(); SDL_Event event; SDL_PollEvent(&event); if (event.type == SDL_QUIT) done = true; else if (event.type == SDL_KEYDOWN) KeyboardDown(event.key.keysym.sym); else if (event.type == SDL_KEYUP) KeyboardUp(event.key.keysym.sym); usleep(FRAME_DELAY); } delete modelFile; device->Destroy(); delete device; SDL_FreeSurface(surface); IMG_Quit(); SDL_Quit(); GetSystemUtils()->DestroyTimeStamp(PREV_TIME); GetSystemUtils()->DestroyTimeStamp(CURR_TIME); return 0; } } // extern "C"