mirror of
https://github.com/raysan5/raylib.git
synced 2026-08-24 21:28:27 -04:00
Compare commits
7 Commits
abe23bf82d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e1efefb7f4 | |||
| 2c0021ad89 | |||
| 9bde204f1d | |||
| 47231e37ef | |||
| 0088b85952 | |||
| 338458a92b | |||
| 3836f13878 |
@ -1,6 +1,18 @@
|
||||
# Setup the project and settings
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
project(examples)
|
||||
|
||||
# Include raylib's cmake helper functions, so the examples can also be
|
||||
# configured standalone (`cd examples && cmake .`) and not only as part
|
||||
# of the raylib project.
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake")
|
||||
include(AddIfFlagCompiles)
|
||||
|
||||
# Default to the Desktop platform when configured standalone.
|
||||
if (NOT DEFINED PLATFORM)
|
||||
set(PLATFORM "Desktop" CACHE STRING "Platform to build examples for")
|
||||
endif ()
|
||||
|
||||
# Directories that contain examples
|
||||
set(example_dirs
|
||||
audio
|
||||
|
||||
44
examples/shaders/resources/shaders/glsl100/lights_bloom.fs
Normal file
44
examples/shaders/resources/shaders/glsl100/lights_bloom.fs
Normal file
@ -0,0 +1,44 @@
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input values from vertex shader
|
||||
varying vec3 fragPosition;
|
||||
varying vec3 fragNormal;
|
||||
varying vec2 fragTexCoord;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec3 viewPos;
|
||||
uniform vec3 lightPositions[8];
|
||||
uniform vec3 lightColors[8];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 texColor = texture2D(texture0, fragTexCoord);
|
||||
vec3 norm = normalize(fragNormal);
|
||||
vec3 viewDir = normalize(viewPos - fragPosition);
|
||||
|
||||
vec3 ambient = 0.05*texColor.rgb;
|
||||
vec3 totalDiffuse = vec3(0.0);
|
||||
vec3 totalSpecular = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
vec3 lightDir = normalize(lightPositions[i] - fragPosition);
|
||||
float dist = length(lightPositions[i] - fragPosition);
|
||||
float attenuation = 1.0/(1.0 + 0.8*dist + 0.4*dist*dist);
|
||||
|
||||
// Diffuse shading
|
||||
float diff = max(dot(norm, lightDir), 0.0);
|
||||
totalDiffuse += diff*lightColors[i]*attenuation*1.2;
|
||||
|
||||
// Blinn-Phong specular
|
||||
vec3 halfwayDir = normalize(lightDir + viewDir);
|
||||
float spec = pow(max(dot(norm, halfwayDir), 0.0), 32.0);
|
||||
totalSpecular += spec*lightColors[i]*attenuation*0.8;
|
||||
}
|
||||
|
||||
vec3 result = ambient + (totalDiffuse*texColor.rgb) + totalSpecular;
|
||||
gl_FragColor = vec4(result, texColor.a);
|
||||
}
|
||||
23
examples/shaders/resources/shaders/glsl100/lights_bloom.vs
Normal file
23
examples/shaders/resources/shaders/glsl100/lights_bloom.vs
Normal file
@ -0,0 +1,23 @@
|
||||
#version 100
|
||||
|
||||
// Input vertex attributes
|
||||
attribute vec3 vertexPosition;
|
||||
attribute vec2 vertexTexCoord;
|
||||
attribute vec3 vertexNormal;
|
||||
|
||||
// Output values to fragment shader
|
||||
varying vec3 fragPosition;
|
||||
varying vec3 fragNormal;
|
||||
varying vec2 fragTexCoord;
|
||||
|
||||
// Input uniform values
|
||||
uniform mat4 mvp;
|
||||
uniform mat4 matModel;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
|
||||
fragNormal = normalize(vec3(matModel*vec4(vertexNormal, 0.0)));
|
||||
fragTexCoord = vertexTexCoord;
|
||||
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
#version 100
|
||||
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 fragTexCoord;
|
||||
|
||||
uniform sampler2D texture0;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture2D(texture0, fragTexCoord);
|
||||
|
||||
// High-pass threshold blur: only pixels brighter than 0.75 in any channel contribute
|
||||
vec4 bloom = vec4(0.0);
|
||||
vec2 texel = vec2(1.0/1280.0, 1.0/720.0)*2.5;
|
||||
|
||||
for (int x = -2; x <= 2; x++)
|
||||
{
|
||||
for (int y = -2; y <= 2; y++)
|
||||
{
|
||||
vec4 smp = texture2D(texture0, fragTexCoord + vec2(float(x), float(y))*texel);
|
||||
float brightness = max(smp.r, max(smp.g, smp.b));
|
||||
if (brightness > 0.75) bloom += smp;
|
||||
}
|
||||
}
|
||||
bloom /= 25.0;
|
||||
|
||||
// Combine original with the bloom glow, then Reinhard tone-map back to [0, 1]
|
||||
vec3 hdr = color.rgb + bloom.rgb*1.2;
|
||||
vec3 ldr = hdr/(hdr + vec3(1.0));
|
||||
|
||||
gl_FragColor = vec4(ldr, color.a);
|
||||
}
|
||||
44
examples/shaders/resources/shaders/glsl330/lights_bloom.fs
Normal file
44
examples/shaders/resources/shaders/glsl330/lights_bloom.fs
Normal file
@ -0,0 +1,44 @@
|
||||
#version 330
|
||||
|
||||
// Input values from vertex shader
|
||||
in vec3 fragPosition;
|
||||
in vec3 fragNormal;
|
||||
in vec2 fragTexCoord;
|
||||
|
||||
out vec4 finalColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec3 viewPos;
|
||||
uniform vec3 lightPositions[8];
|
||||
uniform vec3 lightColors[8];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 texColor = texture(texture0, fragTexCoord);
|
||||
vec3 norm = normalize(fragNormal);
|
||||
vec3 viewDir = normalize(viewPos - fragPosition);
|
||||
|
||||
vec3 ambient = 0.05*texColor.rgb;
|
||||
vec3 totalDiffuse = vec3(0.0);
|
||||
vec3 totalSpecular = vec3(0.0);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
vec3 lightDir = normalize(lightPositions[i] - fragPosition);
|
||||
float dist = length(lightPositions[i] - fragPosition);
|
||||
float attenuation = 1.0/(1.0 + 0.8*dist + 0.4*dist*dist);
|
||||
|
||||
// Diffuse shading
|
||||
float diff = max(dot(norm, lightDir), 0.0);
|
||||
totalDiffuse += diff*lightColors[i]*attenuation*1.2;
|
||||
|
||||
// Blinn-Phong specular
|
||||
vec3 halfwayDir = normalize(lightDir + viewDir);
|
||||
float spec = pow(max(dot(norm, halfwayDir), 0.0), 32.0);
|
||||
totalSpecular += spec*lightColors[i]*attenuation*0.8;
|
||||
}
|
||||
|
||||
vec3 result = ambient + (totalDiffuse*texColor.rgb) + totalSpecular;
|
||||
finalColor = vec4(result, texColor.a);
|
||||
}
|
||||
23
examples/shaders/resources/shaders/glsl330/lights_bloom.vs
Normal file
23
examples/shaders/resources/shaders/glsl330/lights_bloom.vs
Normal file
@ -0,0 +1,23 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes
|
||||
in vec3 vertexPosition;
|
||||
in vec2 vertexTexCoord;
|
||||
in vec3 vertexNormal;
|
||||
|
||||
// Output values to fragment shader
|
||||
out vec3 fragPosition;
|
||||
out vec3 fragNormal;
|
||||
out vec2 fragTexCoord;
|
||||
|
||||
// Input uniform values
|
||||
uniform mat4 mvp;
|
||||
uniform mat4 matModel;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
|
||||
fragNormal = normalize(vec3(matModel*vec4(vertexNormal, 0.0)));
|
||||
fragTexCoord = vertexTexCoord;
|
||||
gl_Position = mvp*vec4(vertexPosition, 1.0);
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
#version 330
|
||||
|
||||
in vec2 fragTexCoord;
|
||||
out vec4 finalColor;
|
||||
|
||||
uniform sampler2D texture0;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color = texture(texture0, fragTexCoord);
|
||||
|
||||
// High-pass threshold blur: only pixels brighter than 0.75 in any channel contribute
|
||||
vec4 bloom = vec4(0.0);
|
||||
vec2 texel = vec2(1.0/1280.0, 1.0/720.0)*2.5;
|
||||
|
||||
for (int x = -2; x <= 2; x++)
|
||||
{
|
||||
for (int y = -2; y <= 2; y++)
|
||||
{
|
||||
vec4 smp = texture(texture0, fragTexCoord + vec2(float(x), float(y))*texel);
|
||||
float brightness = max(smp.r, max(smp.g, smp.b));
|
||||
if (brightness > 0.75) bloom += smp;
|
||||
}
|
||||
}
|
||||
bloom /= 25.0;
|
||||
|
||||
// Combine original with the bloom glow, then Reinhard tone-map back to [0, 1]
|
||||
vec3 hdr = color.rgb + bloom.rgb*1.2;
|
||||
vec3 ldr = hdr/(hdr + vec3(1.0));
|
||||
|
||||
finalColor = vec4(ldr, color.a);
|
||||
}
|
||||
185
examples/shaders/shaders_lights_bloom.c
Normal file
185
examples/shaders/shaders_lights_bloom.c
Normal file
@ -0,0 +1,185 @@
|
||||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - forward multi-lighting with bloom
|
||||
*
|
||||
* Example demonstrates forward multi-point lighting (8 point lights, attenuation and
|
||||
* Blinn-Phong specular) combined with a threshold-based bloom pass and Reinhard tone
|
||||
* mapping, applied as a full-screen post-process pass
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example uses resources/shaders/glsl100 and resources/shaders/glsl330, shared with the
|
||||
* rest of the shaders examples
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by PanicTitan (@PanicTitan) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 PanicTitan (@PanicTitan)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include "raymath.h"
|
||||
#include "rlgl.h"
|
||||
|
||||
#include <math.h> // Required for: sinf(), cosf()
|
||||
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
#define GLSL_VERSION 330
|
||||
#else // PLATFORM_ANDROID, PLATFORM_WEB
|
||||
#define GLSL_VERSION 100
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Global Definitions
|
||||
//--------------------------------------------------------------------------------------
|
||||
#define MAX_LIGHTS 8
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - forward multi-lighting bloom");
|
||||
|
||||
Camera3D camera = { 0 };
|
||||
camera.position = (Vector3){ 0.0f, 5.0f, 9.0f };
|
||||
camera.target = (Vector3){ 0.0f, 0.5f, 0.0f };
|
||||
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
|
||||
camera.fovy = 45.0f;
|
||||
camera.projection = CAMERA_PERSPECTIVE;
|
||||
|
||||
RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
|
||||
// Forward multi-light shader and bloom post-process shader, both loaded from the
|
||||
// resources folder shared with the rest of the shaders examples. If the GLSL version
|
||||
// guessed from the PLATFORM_DESKTOP build flag turns out to be wrong for whatever
|
||||
// raylib was built against, linking fails and silently falls back to the default
|
||||
// shader - so this retries once with the other version, and either way the result
|
||||
// is checked explicitly and reported on screen rather than staying silently wrong
|
||||
Shader lightShader = LoadShader(TextFormat("resources/shaders/glsl%i/lights_bloom.vs", GLSL_VERSION),
|
||||
TextFormat("resources/shaders/glsl%i/lights_bloom.fs", GLSL_VERSION));
|
||||
Shader bloomShader = LoadShader(0, TextFormat("resources/shaders/glsl%i/lights_bloom_post.fs", GLSL_VERSION));
|
||||
|
||||
// Load models from generated cube mesh and plane
|
||||
// NOTE: Meshes are automatically unloaded on UnloadModel()
|
||||
Model cube = LoadModelFromMesh(GenMeshCube(2.0f, 2.0f, 2.0f));
|
||||
Model floor = LoadModelFromMesh(GenMeshPlane(14.0f, 14.0f, 1, 1));
|
||||
cube.materials[0].shader = lightShader;
|
||||
floor.materials[0].shader = lightShader;
|
||||
|
||||
int lightPosLoc = GetShaderLocation(lightShader, "lightPositions");
|
||||
int lightColLoc = GetShaderLocation(lightShader, "lightColors");
|
||||
int viewPosLoc = GetShaderLocation(lightShader, "viewPos");
|
||||
|
||||
Vector3 lightPositions[MAX_LIGHTS] = { 0 };
|
||||
Vector3 lightColors[MAX_LIGHTS] = {
|
||||
{ 1.0f, 0.2f, 0.2f }, // Red
|
||||
{ 0.2f, 1.0f, 0.3f }, // Green
|
||||
{ 0.2f, 0.5f, 1.0f }, // Blue
|
||||
{ 1.0f, 0.8f, 0.1f }, // Yellow
|
||||
{ 1.0f, 0.1f, 0.8f }, // Magenta
|
||||
{ 0.1f, 1.0f, 1.0f }, // Cyan
|
||||
{ 1.0f, 0.4f, 0.1f }, // Orange
|
||||
{ 0.7f, 0.2f, 1.0f }, // Purple
|
||||
};
|
||||
|
||||
SetShaderValueV(lightShader, lightColLoc, lightColors, SHADER_UNIFORM_VEC3, MAX_LIGHTS);
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera, CAMERA_ORBITAL);
|
||||
|
||||
float time = (float)GetTime();
|
||||
|
||||
// Orbital path for each point light, its own radius/height offset by index
|
||||
for (int i = 0; i < MAX_LIGHTS; i++)
|
||||
{
|
||||
float angle = (i/(float)MAX_LIGHTS)*2.0f*PI + time*0.6f;
|
||||
float radius = 4.2f + sinf(time*1.2f + i)*0.4f;
|
||||
float height = 1.0f + sinf(time*1.8f + i)*0.6f;
|
||||
|
||||
lightPositions[i] = (Vector3){ sinf(angle)*radius, height, cosf(angle)*radius };
|
||||
}
|
||||
|
||||
SetShaderValueV(lightShader, lightPosLoc, lightPositions, SHADER_UNIFORM_VEC3, MAX_LIGHTS);
|
||||
SetShaderValue(lightShader, viewPosLoc, &camera.position, SHADER_UNIFORM_VEC3);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Render the lit scene to an offscreen texture
|
||||
BeginTextureMode(target);
|
||||
|
||||
ClearBackground((Color){ 12, 12, 18, 255 });
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(cube, (Vector3){ 0.0f, 1.0f, 0.0f }, 1.0f, GRAY);
|
||||
DrawModel(floor, (Vector3){ 0.0f, 0.0f, 0.0f }, 1.0f, DARKGRAY);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Glowing bulbs mark each light's position
|
||||
for (int i = 0; i < MAX_LIGHTS; i++)
|
||||
{
|
||||
Color bulbColor = (Color){
|
||||
(unsigned char)(lightColors[i].x*255),
|
||||
(unsigned char)(lightColors[i].y*255),
|
||||
(unsigned char)(lightColors[i].z*255),
|
||||
255 };
|
||||
|
||||
DrawSphere(lightPositions[i], 0.15f, bulbColor);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
// Present the offscreen texture through the bloom + tone mapping shader
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(BLACK);
|
||||
|
||||
Rectangle srcRec = { 0, 0, (float)target.texture.width, (float)-target.texture.height };
|
||||
|
||||
BeginShaderMode(bloomShader);
|
||||
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
|
||||
DrawTextureRec(target.texture, srcRec, (Vector2){ 0, 0 }, WHITE);
|
||||
EndShaderMode();
|
||||
|
||||
DrawText("BALANCED MULTI-LIGHT + REINHARD TONE MAPPED BLOOM", 20, 20, 20, GREEN);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModel(cube);
|
||||
UnloadModel(floor);
|
||||
UnloadShader(lightShader);
|
||||
UnloadShader(bloomShader);
|
||||
UnloadRenderTexture(target);
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
examples/shaders/shaders_lights_bloom.png
Normal file
BIN
examples/shaders/shaders_lights_bloom.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 203 KiB |
224
examples/textures/textures_portal_window.c
Normal file
224
examples/textures/textures_portal_window.c
Normal file
@ -0,0 +1,224 @@
|
||||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [textures] example - portal window
|
||||
*
|
||||
* Example demonstrates rendering a second scene to a texture and projecting it onto a
|
||||
* quad to create the illusion of a portal window looking into another place. The second
|
||||
* scene is rendered with an off-axis ("oblique frustum") projection matched to the
|
||||
* viewer's actual position relative to the window, so the illusion holds up correctly
|
||||
* as the player moves and looks around, rather than only looking right from one spot
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by PanicTitan (@PanicTitan) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 PanicTitan (@PanicTitan)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
#include "rlgl.h"
|
||||
#include <math.h>
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//------------------------------------------------------------------------------------
|
||||
static void BeginPortalMode3D(Vector3 eye, Vector3 bottomLeft, Vector3 bottomRight, Vector3 topLeft, float nearPlane, float farPlane);
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [textures] example - portal window");
|
||||
|
||||
// Camera to navigate the "real world" (Dimension A)
|
||||
Camera3D camera = { 0 };
|
||||
camera.position = (Vector3){ 0.0f, 2.5f, 7.0f };
|
||||
camera.target = (Vector3){ 0.0f, 1.8f, 0.0f };
|
||||
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
|
||||
camera.fovy = 45.0f;
|
||||
camera.projection = CAMERA_PERSPECTIVE;
|
||||
|
||||
// The archway opening, in Dimension A world space (used both to draw the frame and
|
||||
// as the window rectangle the oblique projection is built from)
|
||||
Vector3 archBottomLeft = { -1.5f, 0.0f, 0.0f };
|
||||
Vector3 archBottomRight = { 1.5f, 0.0f, 0.0f };
|
||||
Vector3 archTopLeft = { -1.5f, 4.0f, 0.0f };
|
||||
|
||||
// The archway sits at portalA and looks out onto portalB, far away in world space.
|
||||
// Every frame, Dimension B gets rendered to a texture using the same relative eye
|
||||
// and window position, shifted by the offset between the two portals
|
||||
Vector3 portalA = { 0.0f, 0.0f, 0.0f };
|
||||
Vector3 portalB = { 0.0f, 0.0f, -60.0f };
|
||||
RenderTexture2D portalView = LoadRenderTexture(480, 640);
|
||||
|
||||
DisableCursor(); // Lock cursor for first-person free camera controls
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera, CAMERA_FREE);
|
||||
float time = (float)GetTime();
|
||||
|
||||
// Eye and window corners, shifted into Dimension B so they match the player's
|
||||
// actual position and viewing angle relative to the archway
|
||||
Vector3 offset = Vector3Subtract(portalB, portalA);
|
||||
Vector3 eyeInB = Vector3Add(camera.position, offset);
|
||||
Vector3 blInB = Vector3Add(archBottomLeft, offset);
|
||||
Vector3 brInB = Vector3Add(archBottomRight, offset);
|
||||
Vector3 tlInB = Vector3Add(archTopLeft, offset);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Render Dimension B into an offscreen texture, using an oblique projection so
|
||||
// its perspective lines up with the archway exactly as the real camera sees it
|
||||
BeginTextureMode(portalView);
|
||||
|
||||
ClearBackground((Color){ 10, 5, 20, 255 });
|
||||
|
||||
BeginPortalMode3D(eyeInB, blInB, brInB, tlInB, 0.05f, 100.0f);
|
||||
|
||||
DrawGrid(30, 0.8f);
|
||||
|
||||
// Floating pulsing core sphere
|
||||
Vector3 corePos = Vector3Add(portalB, (Vector3){ 0.0f, 2.0f + sinf(time * 2.5f) * 0.4f, -4.0f });
|
||||
DrawSphere(corePos, 1.2f, PURPLE);
|
||||
DrawSphereWires(corePos, 1.25f, 16, 16, MAGENTA);
|
||||
|
||||
// Orbiting cubes
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float angle = time * 1.5f + i * (PI / 2.0f);
|
||||
Vector3 pos = Vector3Add(portalB, (Vector3){
|
||||
sinf(angle) * 2.5f,
|
||||
2.0f + cosf(time * 3.0f + i) * 0.5f,
|
||||
-4.0f + cosf(angle) * 2.5f });
|
||||
|
||||
DrawCube(pos, 0.5f, 0.5f, 0.5f, LIME);
|
||||
DrawCubeWires(pos, 0.52f, 0.52f, 0.52f, DARKGREEN);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground((Color){ 15, 18, 26, 255 });
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(20, 1.0f);
|
||||
|
||||
// Side pillars
|
||||
DrawCube((Vector3){ -3.5f, 2.0f, 0.0f }, 0.8f, 4.0f, 0.8f, DARKGRAY);
|
||||
DrawCubeWires((Vector3){ -3.5f, 2.0f, 0.0f }, 0.8f, 4.0f, 0.8f, ORANGE);
|
||||
DrawCube((Vector3){ 3.5f, 2.0f, 0.0f }, 0.8f, 4.0f, 0.8f, DARKGRAY);
|
||||
DrawCubeWires((Vector3){ 3.5f, 2.0f, 0.0f }, 0.8f, 4.0f, 0.8f, ORANGE);
|
||||
|
||||
// Golden archway frame and solid base
|
||||
DrawCubeWires((Vector3){ 0.0f, 2.0f, 0.0f }, 3.2f, 4.2f, 0.2f, GOLD);
|
||||
DrawCube((Vector3){ 0.0f, 0.05f, 0.0f }, 3.4f, 0.1f, 0.6f, MAROON);
|
||||
|
||||
// Solid backing wall, only ever seen if looking at the archway from behind
|
||||
DrawCube((Vector3){ 0.0f, 2.0f, -0.05f }, 3.1f, 4.1f, 0.05f, DARKBLUE);
|
||||
|
||||
// The portal opening itself: a plain quad textured with the Dimension B
|
||||
// render, filling the archway exactly, so nothing "leaks" outside its shape
|
||||
rlSetTexture(portalView.texture.id);
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(255, 255, 255, 255);
|
||||
rlNormal3f(0.0f, 0.0f, 1.0f);
|
||||
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(archBottomLeft.x, archBottomLeft.y, archBottomLeft.z);
|
||||
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(archBottomRight.x, archBottomRight.y, archBottomRight.z);
|
||||
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(archBottomRight.x, 4.0f, archBottomRight.z);
|
||||
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(archTopLeft.x, archTopLeft.y, archTopLeft.z);
|
||||
rlEnd();
|
||||
rlSetTexture(0);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// HUD overlay
|
||||
DrawRectangle(15, 15, 400, 85, Fade(BLACK, 0.75f));
|
||||
DrawRectangleLines(15, 15, 400, 85, GOLD);
|
||||
DrawText("PORTAL WINDOW", 28, 25, 20, GOLD);
|
||||
DrawText("Look through the golden arch into Dimension B", 28, 52, 14, RAYWHITE);
|
||||
DrawText("Controls: Mouse to look | WASD to move", 28, 72, 12, GRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadRenderTexture(portalView);
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Starts a 3D mode using an off-axis ("oblique frustum") projection, built directly from
|
||||
// an eye point and 3 corners of a rectangular window, instead of a fovy centered straight
|
||||
// ahead of the camera. This is the standard technique for rendering a scene as seen through
|
||||
// a window that isn't necessarily faced head-on (also used for multi-monitor and VR
|
||||
// rendering) - the key difference from a normal Camera3D is that the frustum is allowed
|
||||
// to be asymmetric, so perspective lines through the window line up correctly from any
|
||||
// eye position, instead of behaving like a flat image pasted onto the window
|
||||
static void BeginPortalMode3D(Vector3 eye, Vector3 bottomLeft, Vector3 bottomRight, Vector3 topLeft, float nearPlane, float farPlane)
|
||||
{
|
||||
Vector3 right = Vector3Normalize(Vector3Subtract(bottomRight, bottomLeft));
|
||||
Vector3 up = Vector3Normalize(Vector3Subtract(topLeft, bottomLeft));
|
||||
Vector3 normal = Vector3Normalize(Vector3CrossProduct(right, up));
|
||||
|
||||
// Vectors from the eye to 3 corners of the window, used to project the window onto
|
||||
// the near plane and read off how far it extends left/right/bottom/top of the eye
|
||||
Vector3 toBL = Vector3Subtract(bottomLeft, eye);
|
||||
Vector3 toBR = Vector3Subtract(bottomRight, eye);
|
||||
Vector3 toTL = Vector3Subtract(topLeft, eye);
|
||||
|
||||
float dist = -Vector3DotProduct(toBL, normal);
|
||||
if (dist < 0.01f) dist = 0.01f; // Keep the eye from crossing the window plane
|
||||
|
||||
float scale = nearPlane/dist;
|
||||
|
||||
rlDrawRenderBatchActive();
|
||||
|
||||
rlMatrixMode(RL_PROJECTION);
|
||||
rlPushMatrix();
|
||||
rlSetMatrixProjection(MatrixFrustum(
|
||||
Vector3DotProduct(right, toBL)*scale, Vector3DotProduct(right, toBR)*scale,
|
||||
Vector3DotProduct(up, toBL)*scale, Vector3DotProduct(up, toTL)*scale,
|
||||
nearPlane, farPlane));
|
||||
|
||||
// View orientation is fixed to the window's own plane (looking straight through it
|
||||
// along its normal), NOT aimed at any target - that's what the asymmetric frustum
|
||||
// above is for, and is what lets the eye move off to one side without distorting
|
||||
rlMatrixMode(RL_MODELVIEW);
|
||||
rlLoadIdentity();
|
||||
rlMultMatrixf(MatrixToFloat(MatrixLookAt(eye, Vector3Subtract(eye, normal), up)));
|
||||
|
||||
rlEnableDepthTest();
|
||||
}
|
||||
BIN
examples/textures/textures_portal_window.png
Normal file
BIN
examples/textures/textures_portal_window.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@ -114,6 +114,20 @@ if (NOT BUILD_SHARED_LIBS)
|
||||
|
||||
if (NOT glfw3_FOUND)
|
||||
list(REMOVE_ITEM raylib_install_private_libs glfw)
|
||||
|
||||
# Bundled GLFW links its Cocoa backend frameworks privately, so they
|
||||
# must be propagated to consumers of the static library, whose final
|
||||
# link line would otherwise miss them. Only the Desktop platform uses
|
||||
# bundled GLFW; other platforms (e.g. Memory) have no Cocoa/GLFW symbols.
|
||||
if (APPLE AND PLATFORM STREQUAL "Desktop")
|
||||
find_library(COCOA_FRAMEWORK Cocoa)
|
||||
find_library(IOKIT_FRAMEWORK IOKit)
|
||||
find_library(QUARTZCORE_FRAMEWORK QuartzCore)
|
||||
list(APPEND raylib_install_private_libs
|
||||
${COCOA_FRAMEWORK}
|
||||
${IOKIT_FRAMEWORK}
|
||||
${QUARTZCORE_FRAMEWORK})
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
foreach(lib IN LISTS raylib_install_private_libs)
|
||||
|
||||
1
src/external/fix_win32_compatibility.h
vendored
1
src/external/fix_win32_compatibility.h
vendored
@ -46,6 +46,7 @@
|
||||
// include windows
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <playsoundapi.h>
|
||||
|
||||
// remove all our redefinitions so that raylib can define them properly
|
||||
#undef CloseWindow
|
||||
|
||||
@ -588,7 +588,7 @@ int main(int argc, char *argv[])
|
||||
else if (TextIsEqual(exCategory, "text")) nextCategoryIndex = 4;
|
||||
else if (TextIsEqual(exCategory, "models")) nextCategoryIndex = 5;
|
||||
else if (TextIsEqual(exCategory, "shaders")) nextCategoryIndex = 6;
|
||||
else if (TextIsEqual(exCategory, "audio")) nextCategoryIndex = 7;
|
||||
else if (TextIsEqual(exCategory, "audio")) nextCategoryIndex = -1; // EOF, "audio" is the last category, avoid out-of-bounds exCategories[7] access
|
||||
|
||||
// Get required example info from example file header (if provided)
|
||||
|
||||
@ -621,7 +621,13 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
{
|
||||
// Add example to collection, at the end of the category list
|
||||
int categoryIndex = TextFindIndex(exCollectionList, exCategories[nextCategoryIndex]);
|
||||
// NOTE: Search is anchored to "\n<category>;" (not just "<category>") to avoid
|
||||
// false-positive matches when one category name is a text-prefix of another
|
||||
// (e.g. "text" is a prefix of "textures", so a bare search for "text" matches
|
||||
// inside "core_render_texture" or at the start of the "textures" block instead
|
||||
// of the actual "text" category boundary, corrupting the collection list)
|
||||
int categoryIndex = TextFindIndex(exCollectionList, TextFormat("\n%s;", exCategories[nextCategoryIndex])) + 1;
|
||||
if (categoryIndex == 0) categoryIndex = (int)strlen(exCollectionList); // Category not found, fallback to EOF
|
||||
memcpy(exCollectionListUpdated, exCollectionList, categoryIndex);
|
||||
int textWritenSize = sprintf(exCollectionListUpdated + categoryIndex, TextFormat("%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n",
|
||||
exInfo->category, exInfo->name, starsText, exInfo->verCreated, exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed, exInfo->author, exInfo->authorGitHub));
|
||||
@ -1030,8 +1036,16 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Find position to add new example on list, just before the following category
|
||||
// Category order: core, shapes, textures, text, models, shaders, audio
|
||||
// NOTE: Search is anchored to "\n<category>;" (not just "\n<category>") to avoid
|
||||
// false-positive matches when one category name is a text-prefix of another
|
||||
// (e.g. "text" is a prefix of "textures", so a bare "\ntext" search matches the
|
||||
// START of the "textures" block instead of the actual "text" category boundary).
|
||||
int exListNextCatIndex = -1;
|
||||
if (nextCatIndex != -1) exListNextCatIndex = TextFindIndex(exList, TextFormat("\n%s", exCategories[nextCatIndex])) + 1;
|
||||
if (nextCatIndex != -1)
|
||||
{
|
||||
exListNextCatIndex = TextFindIndex(exList, TextFormat("\n%s;", exCategories[nextCatIndex])) + 1;
|
||||
if (exListNextCatIndex == 0) exListNextCatIndex = exListLen; // Category not found, fallback to EOF
|
||||
}
|
||||
else exListNextCatIndex = exListLen; // EOF
|
||||
|
||||
strncpy(exListUpdated, exList, exListNextCatIndex);
|
||||
|
||||
Reference in New Issue
Block a user