/*---------------------------------------------------------------------------* Project: Horizon File: Fog.cpp Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 47228 $ *---------------------------------------------------------------------------*/ /* *------------------------------------------------------------ * Copyright(c) 2009-2010 by Digital Media Professionals Inc. * All rights reserved. *------------------------------------------------------------ * This source code is the confidential and proprietary * of Digital Media Professionals Inc. *------------------------------------------------------------ */ /* * Comments * -------- * * Fog sample. * This sample shows how to set up lookup tables for linear and exponential fog. * The rendered display is split in 2 by the scissor test and is relevant for linear fog. * In that case, the left side of the screen shows a quadrilateral with fog enabled. * The right side shows three different quadrilaterals, corresponding to 3 regions: * i) before the start of the fog, ii) between the start and end of the fog, and iii) after the end of the fog */ #include #include #include #include #include #include #include #include #include "demo.h" /* program id */ GLuint s_PgID; /* shader id */ GLuint s_ShID; /* fog color */ GLfloat s_FogColor[4]={1.0f, 1.0f, 1.0f, 1.0f}; /* fog LUT number */ #define FOG_LUT_NUM (0) /* fog mode settings */ #define FOG_MODE (FOG_MODE_LINEAR) /* Selection of fog mode */ #define FOG_MODE_LINEAR (0) /* GL_LINEAR mode in OpenGL ES1.1 compatible */ #define FOG_MODE_EXP (1) /* GL_EXP mode in OpenGL ES1.1 compatible */ float s_FogStart = 10.f; /* GL_FOG_START in OpenGL ES1.1 compatible settings */ float s_FogEnd = 30.f; /* GL_FOG_END in OpenGL ES1.1 compatible settings */ float s_FogDensity = 0.1f; /* GL_FOG_DENSITY in OpenGL ES1.1 compatible settings */ float s_FogAfter = 500.f; float s_Width = 1000.f; float s_Height = 0.f; /* Buffer ids */ GLuint s_QuadFogIndexBufID; GLuint s_QuadFogVertBufID; GLuint s_QuadFogColBufID; GLuint s_QuadAllIndexBufID; GLuint s_QuadAllVertBufID; GLuint s_QuadAllColBufID; /* Vertex attribute related */ GLfloat s_VertexFog[12]; const GLushort s_QuadIndexAll[18] = { 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 9, 11 }; const GLushort s_QuadIndexFog[6] = {0, 1, 2, 0, 2, 3}; GLfloat s_VertexAll[36]; GLfloat s_VertexAllColor[48]; GLfloat s_VertexFogColor[48]; GLuint s_FogLutID; GLuint s_CollectionLUTID; /* ExpHeap for app. */ nn::fnd::ExpHeap s_AppHeap; uptr s_HeapForGx; const u32 s_GxHeapSize = 0x400000; demo::RenderSystem s_RenderSystem; /* This function returns fog coefficient for input value c */ float FogCoef(float fog_c) { /* GL_LINEAR compatible */ if (FOG_MODE == FOG_MODE_LINEAR) { if (fog_c < s_FogStart) return 1.0f; else if (fog_c > s_FogEnd) return 0.0f; else return (s_FogEnd - fog_c) / (s_FogEnd - s_FogStart); } /* GL_EXP compatible */ else if (FOG_MODE == FOG_MODE_EXP) { return exp(-s_FogDensity * fog_c); } /* Error */ else return -1.0; } void InitializeFogTable(nn::math::Matrix44 *MP) { static float Fog_LUT[256]; /* Fog lut contents */ static float Fog_c[128 + 1]; /* c (distance from origin in eye coordinate */ int i; nn::math::Matrix44 invPM; nn::math::Vector4 v_clip(0.0f, 0.0f, 0.0f, 1.0f); nn::math::Vector4 v_eye; /* If projection matrix is DMPGL2.0 one, USE code following */ nn::math::MTX44Inverse(&invPM, MP); nn::math::Vector4 v0(invPM.m[0]); nn::math::Vector4 v1(invPM.m[1]); nn::math::Vector4 v2(invPM.m[2]); nn::math::Vector4 v3(invPM.m[3]); for (i = 0; i <= 128; i++) { v_clip.z = -(static_cast(i)) / 128; v_eye.x = nn::math::VEC4Dot(&v0, &v_clip); v_eye.y = nn::math::VEC4Dot(&v1, &v_clip); v_eye.z = nn::math::VEC4Dot(&v2, &v_clip); v_eye.w = nn::math::VEC4Dot(&v3, &v_clip); Fog_c[i] = -(v_eye.z / v_eye.w); } for (i = 0; i < 128; i++) { Fog_LUT[i] = FogCoef(Fog_c[i]); Fog_LUT[128 + i]= FogCoef(Fog_c[i + 1]) - FogCoef(Fog_c[i]); } glBindTexture(GL_TEXTURE_COLLECTION_DMP, s_CollectionLUTID); glBindTexture(GL_LUT_TEXTURE0_DMP + FOG_LUT_NUM, s_FogLutID); glTexImage1D(GL_LUT_TEXTURE0_DMP + FOG_LUT_NUM, 0, GL_LUMINANCEF_DMP, 256, 0, GL_LUMINANCEF_DMP, GL_FLOAT, Fog_LUT); } /* load objects */ static void LoadObjects(void) { s_VertexAll[0] = -s_Width; s_VertexAll[1] = s_Height; s_VertexAll[2] = 0; s_VertexAll[3] = s_Width; s_VertexAll[4] = s_Height; s_VertexAll[5] = 0; s_VertexAll[6] = s_Width; s_VertexAll[7] = s_Height; s_VertexAll[8] = s_FogStart; s_VertexAll[9] = -s_Width; s_VertexAll[10] = s_Height; s_VertexAll[11] = s_FogStart; for (int i = 0; i < 4; i++) { s_VertexAllColor[4 * i + 0] = 1.0f; s_VertexAllColor[4 * i + 1] = 0.0f; s_VertexAllColor[4 * i + 2] = 0.0f; s_VertexAllColor[4 * i + 3] = 1.0f; } s_VertexAll[12 + 0] = -s_Width; s_VertexAll[12 + 1] = s_Height; s_VertexAll[12 + 2] = s_FogStart; s_VertexAll[12 + 3] = s_Width; s_VertexAll[12 + 4] = s_Height; s_VertexAll[12 + 5] = s_FogStart; s_VertexAll[12 + 6] = s_Width; s_VertexAll[12 + 7] = s_Height; s_VertexAll[12 + 8] = s_FogEnd; s_VertexAll[12 + 9] = -s_Width; s_VertexAll[12 + 10] = s_Height; s_VertexAll[12 + 11] = s_FogEnd; for (int i = 0; i < 4; i++) { s_VertexAllColor[16 + 4 * i + 0] = 1.0f; s_VertexAllColor[16 + 4 * i + 1] = 1.0f; s_VertexAllColor[16 + 4 * i + 2] = 0.0f; s_VertexAllColor[16 + 4 * i + 3] = 1.0f; } s_VertexAll[24 + 0] = -s_Width; s_VertexAll[24 + 1] = s_Height; s_VertexAll[24 + 2] = s_FogEnd; s_VertexAll[24 + 3] = s_Width; s_VertexAll[24 + 4] = s_Height; s_VertexAll[24 + 5] = s_FogEnd; s_VertexAll[24 + 6] = s_Width; s_VertexAll[24 + 7] = s_Height; s_VertexAll[24 + 8] = s_FogEnd+s_FogAfter; s_VertexAll[24 + 9] = -s_Width; s_VertexAll[24 + 10] = s_Height; s_VertexAll[24 + 11] = s_FogEnd+s_FogAfter; for (int i = 0; i < 4; i++) { s_VertexAllColor[32 + 4 * i + 0] = 1.0f; s_VertexAllColor[32 + 4 * i + 1] = 0.0f; s_VertexAllColor[32 + 4 * i + 2] = 1.0f; s_VertexAllColor[32 + 4 * i + 3] = 1.0f; } s_VertexFog[0] = -s_Width; s_VertexFog[1] = s_Height; s_VertexFog[2] = 0; s_VertexFog[3] = s_Width; s_VertexFog[4] = s_Height; s_VertexFog[5] = 0; s_VertexFog[6] = s_Width; s_VertexFog[7] = s_Height; s_VertexFog[8] = s_FogEnd + s_FogAfter; s_VertexFog[9] = -s_Width; s_VertexFog[10] = s_Height; s_VertexFog[11] = s_FogEnd + s_FogAfter; for (int i = 0; i < 4; i++) { s_VertexFogColor[4 * i + 0] = 0.0f; s_VertexFogColor[4 * i + 1] = 0.0f; s_VertexFogColor[4 * i + 2] = 1.0f; s_VertexFogColor[4 * i + 3] = 1.0f; } glGenBuffers(1, &s_QuadFogIndexBufID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_QuadFogIndexBufID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLushort), &s_QuadIndexFog, GL_STATIC_DRAW); glGenBuffers(1, &s_QuadAllIndexBufID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_QuadAllIndexBufID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 18 * sizeof(GLushort), &s_QuadIndexAll, GL_STATIC_DRAW); glGenBuffers(1, &s_QuadFogVertBufID); glBindBuffer(GL_ARRAY_BUFFER, s_QuadFogVertBufID); glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), &s_VertexFog, GL_STATIC_DRAW); glGenBuffers(1, &s_QuadFogColBufID); glBindBuffer(GL_ARRAY_BUFFER, s_QuadFogColBufID); glBufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), &s_VertexFogColor, GL_STATIC_DRAW); glGenBuffers(1, &s_QuadAllVertBufID); glBindBuffer(GL_ARRAY_BUFFER, s_QuadAllVertBufID); glBufferData(GL_ARRAY_BUFFER, 36 * sizeof(GLfloat), &s_VertexAll, GL_STATIC_DRAW); glGenBuffers(1, &s_QuadAllColBufID); glBindBuffer(GL_ARRAY_BUFFER, s_QuadAllColBufID); glBufferData(GL_ARRAY_BUFFER, 48 * sizeof(GLfloat), &s_VertexAllColor, GL_STATIC_DRAW); } void DrawScene() { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); glViewport(0, 0, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT); s_RenderSystem.Clear(); glDisable(GL_CULL_FACE); glEnable(GL_SCISSOR_TEST); glScissor(0, 0, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT / 2); glBindBuffer(GL_ARRAY_BUFFER, s_QuadAllVertBufID); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, s_QuadAllColBufID); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_QuadAllIndexBufID); glDrawElements(GL_TRIANGLES, 18, GL_UNSIGNED_SHORT, 0); glScissor(0, nn::gx::DISPLAY0_HEIGHT / 2, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT / 2); glUniform1i(glGetUniformLocation(s_PgID, "dmp_Fog.mode"), GL_FOG); glBindBuffer(GL_ARRAY_BUFFER, s_QuadFogVertBufID); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, s_QuadFogColBufID); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s_QuadFogIndexBufID); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT,0); glUniform1i(glGetUniformLocation(s_PgID, "dmp_Fog.mode"), 0); glDisable(GL_SCISSOR_TEST); s_RenderSystem.SwapBuffers(); } int DrawFrame(void) { static int f = 0; static const int step = 128; /* fog_sampler 0 is exponential fog */ /* fog_sampler 1 is linear fog */ glUniform1i(glGetUniformLocation(s_PgID, "dmp_Fog.sampler"), FOG_LUT_NUM); float dx = f * (1.0f / (float)(step - 1)); s_FogColor[0] = 0.2f + dx * (1.0f - 0.2f); s_FogColor[1] = 0.4f + dx * (1.0f - 0.4f); s_FogColor[2] = 0.6f + dx * (1.0f - 0.6f); glUniform3fv(glGetUniformLocation(s_PgID, "dmp_Fog.color"), 1, s_FogColor); DrawScene(); s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); s_RenderSystem.Clear(); s_RenderSystem.SwapBuffers(); s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); if (f == step - 1) f=0; else f++; return !glGetError(); } /* initialization */ static int Initialize(void) { // fs initialization nn::fs::Initialize(); const size_t ROMFS_BUFFER_SIZE = 1024 * 64; static char buffer[ROMFS_BUFFER_SIZE]; NN_UTIL_PANIC_IF_FAILED( nn::fs::MountRom(16, 16, buffer, ROMFS_BUFFER_SIZE)); s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() ); s_HeapForGx = reinterpret_cast(s_AppHeap.Allocate(s_GxHeapSize)); /* Initialize display */ s_RenderSystem.Initialize(s_HeapForGx, s_GxHeapSize); glClearColor(0.2f, 0.4f, 0.6f, 1.0f); glClearDepthf(1.f); glViewport(0, 0, nn::gx::DISPLAY0_WIDTH, nn::gx::DISPLAY0_HEIGHT); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glCullFace(GL_BACK); /* create program and load & attach vertex shader */ s_PgID = glCreateProgram(); s_ShID = glCreateShader(GL_VERTEX_SHADER); nn::fs::FileReader file(L"rom:/shader.shbin"); size_t fileSize = file.GetSize(); void* buf = s_AppHeap.Allocate(fileSize); s32 read = file.Read(buf, fileSize); glShaderBinary(1, &s_ShID, GL_PLATFORM_BINARY_DMP, buf, read); file.Finalize(); s_AppHeap.Free(buf); glAttachShader(s_PgID, s_ShID); /* attach fixed-function fragment shader */ glAttachShader(s_PgID, GL_DMP_FRAGMENT_SHADER_DMP); glBindAttribLocation(s_PgID, 0, "aPosition"); glBindAttribLocation(s_PgID, 1, "aColor"); glLinkProgram(s_PgID); glValidateProgram(s_PgID); /* set program as current one to enable setting its uniforms */ glUseProgram(s_PgID); LoadObjects(); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcRgb"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); glUniform3i(glGetUniformLocation(s_PgID, "dmp_TexEnv[0].srcAlpha"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); nn::math::Matrix44 proj; nn::math::MTX44Perspective(&proj, 65.0f, static_cast(nn::gx::DISPLAY0_WIDTH) / static_cast(nn::gx::DISPLAY0_HEIGHT), 1.0f, 500.0f); glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uProjection"), 1, GL_TRUE, static_cast(proj)); nn::math::Matrix34 eye; nn::math::Vector3 camPos(0.0f, 2.0f, 0.0f); nn::math::Vector3 camUp(1.0f, 0.0f, 0.0f); nn::math::Vector3 target(0.0f, 2.0f, 10.0f); nn::math::MTX34Identity(&eye); nn::math::MTX34LookAt(&eye, &camPos, &camUp, &target); nn::math::Matrix44 mv(eye); glUniformMatrix4fv(glGetUniformLocation(s_PgID, "uModelView"), 1, GL_TRUE, static_cast(mv)); glGenTextures(1, &s_CollectionLUTID); glGenTextures(1, &s_FogLutID); InitializeFogTable(&proj); return 0; } void nnMain(void) { // Call only nn::applet::Enable to also allow execution from the HOME Menu // HOME Menu transitions, POWER Button presses, and sleep are all unsupported nn::applet::Enable(); /* initialization */ if (Initialize() >= 0) { while (1) { (void)DrawFrame(); } } /* shutdown_display */ s_RenderSystem.Finalize(); s_AppHeap.Free(reinterpret_cast(s_HeapForGx)); s_AppHeap.Finalize(); }