All public snippets from the HMN GitLab
This commit is contained in:
commit
e29ec6c1ca
|
@ -0,0 +1,63 @@
|
||||||
|
Useful FFMPEG commands:
|
||||||
|
|
||||||
|
Turn video into images, 1 image per 5 seconds:
|
||||||
|
ffmpeg -i Day_11_part_1.mp4 -vf fps=1/5 -start_number 0 %06d.png
|
||||||
|
|
||||||
|
Turn images into a slideshow:
|
||||||
|
ffmpeg -framerate 30 -i %06d.png -c:v libx264 -r 30 -pix_fmt yuv420p Timelapse.mp4
|
||||||
|
|
||||||
|
Turn 1 image into a 3 second video:
|
||||||
|
ffmpeg -framerate 1/3 -i 6.png -c:v libx264 -r 30 -pix_fmt yuv420p 6.mp4
|
||||||
|
|
||||||
|
Extract audio
|
||||||
|
ffmpeg -i Day07c.mp4 -c:a copy -vn audio.aac
|
||||||
|
|
||||||
|
Extract video:
|
||||||
|
ffmpeg -i Day07c.mp4 -c:v copy -an video.mp4
|
||||||
|
|
||||||
|
Mux video and audio back together:
|
||||||
|
ffmpeg -i Timelapse.aac -i Timelapse.mp4 -c:v copy -c:a copy -bsf:a aac_adtstoasc TimelapseNew.mp4
|
||||||
|
|
||||||
|
Mux like before, but also stop encoding when the shortest file runs out
|
||||||
|
ffmpeg -framerate 60 -i %06d.png -c:v libx264 -r 60 -pix_fmt yuv420p -i audiofile.mp3 -c:a copy -filter_complex " [1:0] apad " -shortest vidya.mp4
|
||||||
|
|
||||||
|
Concat simple:
|
||||||
|
ffmpeg -f concat -i a.txt Timelapse.aac
|
||||||
|
|
||||||
|
Concat advanced:
|
||||||
|
ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
|
||||||
|
ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
|
||||||
|
ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4
|
||||||
|
|
||||||
|
Copy a 58m part of a video, starting 2h33m20s in to another video:
|
||||||
|
ffmpeg -ss 02:33:20 -i Day07c.mp4 -t 00:58:00 -c:a copy -c:v copy -bsf:a aac_adtstoasc 3.mp4
|
||||||
|
|
||||||
|
# Quality settings
|
||||||
|
|
||||||
|
echo Default quality (-crf 23) - 2041kb/s avg
|
||||||
|
ffmpeg -framerate 60 -i "frame_%%09d.png" -c:v libx264 -r 60 -pix_fmt yuv420p quality_23_default.mp4
|
||||||
|
|
||||||
|
echo Lossless - 5444kb/s avg
|
||||||
|
ffmpeg -framerate 60 -i "frame_%%09d.png" -c:v libx264 -r 60 -preset veryslow -qp 0 -pix_fmt yuv420p lossless.mp4
|
||||||
|
# If you care just about the quality and are going to upload it to YT,
|
||||||
|
# you could use -preset veryfast or -preset ultrafast to still get lossless, but without as long a wait
|
||||||
|
|
||||||
|
echo Default quality, animation - 1828kb/s avg
|
||||||
|
ffmpeg -framerate 60 -i "frame_%%09d.png" -c:v libx264 -r 60 -tune animation -pix_fmt yuv420p quality_23_default_anim_tuned.mp4
|
||||||
|
|
||||||
|
echo Lossless, animation - 5447kb/s avg
|
||||||
|
ffmpeg -framerate 60 -i "frame_%%09d.png" -c:v libx264 -r 60 -tune animation -preset veryslow -qp 0 -pix_fmt yuv420p lossless_anim_tuned.mp4
|
||||||
|
|
||||||
|
echo Quality level 22 - 2239kb/s avg
|
||||||
|
ffmpeg -framerate 60 -i "frame_%%09d.png" -c:v libx264 -r 60 -crf 22 -pix_fmt yuv420p quality_22.mp4
|
||||||
|
|
||||||
|
echo Quality level 22, animation - 1998kb/s avg
|
||||||
|
ffmpeg -framerate 60 -i "frame_%%09d.png" -c:v libx264 -r 60 -tune animation -crf 22 -pix_fmt yuv420p quality_22_anim_tuned.mp4
|
||||||
|
|
||||||
|
echo Quality level 18 - 3069kb/s avg
|
||||||
|
ffmpeg -framerate 60 -i "frame_%%09d.png" -c:v libx264 -r 60 -crf 18 -pix_fmt yuv420p quality_18.mp4
|
||||||
|
|
||||||
|
echo Quality level 18, animation - 2740kb/s avg
|
||||||
|
ffmpeg -framerate 60 -i "frame_%%09d.png" -c:v libx264 -r 60 -tune animation -crf 18 -pix_fmt yuv420p quality_18_anim_tuned.mp4
|
||||||
|
|
||||||
|
For more quality settings, see: https://trac.ffmpeg.org/wiki/Encode/H.264
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
target = '3.14159263'
|
||||||
|
# target = '3.14159263589'
|
||||||
|
digits = len(target) - 2
|
||||||
|
power = pow(10, digits)
|
||||||
|
target = int(float(target) * power)
|
||||||
|
|
||||||
|
result = 0
|
||||||
|
divisor = -1
|
||||||
|
step = 0
|
||||||
|
count = -1
|
||||||
|
count2 = 0
|
||||||
|
subtract = False
|
||||||
|
|
||||||
|
close = False
|
||||||
|
r4 = 0
|
||||||
|
|
||||||
|
while (not close):
|
||||||
|
count = count + 1
|
||||||
|
divisor = divisor + 2
|
||||||
|
|
||||||
|
step = 1 / divisor
|
||||||
|
if subtract == True:
|
||||||
|
result = result - step
|
||||||
|
subtract = False
|
||||||
|
else:
|
||||||
|
result = result + step
|
||||||
|
subtract = True
|
||||||
|
|
||||||
|
r4 = result * 4
|
||||||
|
|
||||||
|
if count2 == 100000:
|
||||||
|
print("Step: %10d | Fraction: 1/%10d = %1.12f | Result: %1.12f | Result * 4: %1.12f" % (count, divisor, step, result, r4))
|
||||||
|
count2 = 0
|
||||||
|
|
||||||
|
if int(r4 * power) == target:
|
||||||
|
close = True
|
||||||
|
|
||||||
|
count2 = count2 + 1
|
||||||
|
|
||||||
|
print("Step: %10d | Fraction: 1/%10d = %1.12f | Result: %1.12f | Result * 4: %1.12f" % (count , divisor, step, result, r4))
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* This file is automatically generated.
|
||||||
|
It defines a symbol `__stub_FUNCTION' for each function
|
||||||
|
in the C library which is a stub, meaning it will fail
|
||||||
|
every time called, usually setting errno to ENOSYS. */
|
||||||
|
|
||||||
|
#ifdef _LIBC
|
||||||
|
# error Applications may not define the macro _LIBC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __stub_bdflush
|
||||||
|
#define __stub_chflags
|
||||||
|
#define __stub_fattach
|
||||||
|
#define __stub_fchflags
|
||||||
|
#define __stub_fdetach
|
||||||
|
#define __stub_getmsg
|
||||||
|
#define __stub_gtty
|
||||||
|
#define __stub_lchmod
|
||||||
|
#define __stub_putmsg
|
||||||
|
#define __stub_revoke
|
||||||
|
#define __stub_setlogin
|
||||||
|
#define __stub_sigreturn
|
||||||
|
#define __stub_sstk
|
||||||
|
#define __stub_stty
|
|
@ -0,0 +1,118 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from datetime import datetime, date, timedelta
|
||||||
|
import sys
|
||||||
|
# this is optional, to autolink mentioned urls if format --html is chosen
|
||||||
|
# if you don't have it, also comment out line 96
|
||||||
|
from bleach import linkify
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
#print(sys.argv)
|
||||||
|
if len(sys.argv) < 2 or (len(sys.argv) > 1 and sys.argv[1] == '-h'):
|
||||||
|
print("Usage: %s <logname> [offset-in-hours] [--html]" % sys.argv[0])
|
||||||
|
exit()
|
||||||
|
elif len(sys.argv) >= 2:
|
||||||
|
filename = sys.argv[1]
|
||||||
|
offset = 0
|
||||||
|
elif len(sys.argv) >= 3:
|
||||||
|
filename = sys.argv[1]
|
||||||
|
offset = int(sys.argv[2])
|
||||||
|
if len(sys.argv) >= 4 and sys.argv[3] == '--html':
|
||||||
|
formatting = 'html'
|
||||||
|
else:
|
||||||
|
formatting = 'plain'
|
||||||
|
|
||||||
|
today = date.today()
|
||||||
|
delta = timedelta(hours=offset)
|
||||||
|
nickcolor = {}
|
||||||
|
log = []
|
||||||
|
colors = ['red', 'blue', 'green', 'yellow', 'teal', 'purple']
|
||||||
|
max_nick = 0
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
when = line[:15]
|
||||||
|
when_parsed = datetime.strptime(when, '%b %d %H:%M:%S').replace(year=today.year)
|
||||||
|
when_est = when_parsed + delta
|
||||||
|
what = line[15:]
|
||||||
|
if what[1] == '<':
|
||||||
|
nick_start = 2
|
||||||
|
nick_end = what.find('>')
|
||||||
|
nick = what[nick_start:nick_end].strip()
|
||||||
|
if not nick in nickcolor:
|
||||||
|
nickcolor[nick] = colors[0]
|
||||||
|
colors = colors[1:] + [colors[0]]
|
||||||
|
|
||||||
|
if len(nick) > max_nick:
|
||||||
|
max_nick = len(nick)
|
||||||
|
|
||||||
|
what = what[nick_end + 2:].strip('\n')
|
||||||
|
|
||||||
|
log.append(dict(when=when_est, nick=nick, what=what))
|
||||||
|
|
||||||
|
elif what[1] == '*':
|
||||||
|
nick_start = 3
|
||||||
|
nick_end = what.find('\s')
|
||||||
|
what = what[nick_start:nick_end].strip()
|
||||||
|
nick_start = 0
|
||||||
|
nick_end = what.find(' ')
|
||||||
|
nick = what[nick_start:nick_end].strip()
|
||||||
|
if not nick in nickcolor:
|
||||||
|
nickcolor[nick] = colors[0]
|
||||||
|
colors = colors[1:] + [colors[0]]
|
||||||
|
|
||||||
|
if len(nick) > max_nick:
|
||||||
|
max_nick = len(nick)
|
||||||
|
|
||||||
|
what = what[nick_end + 1:].strip('\n')
|
||||||
|
|
||||||
|
log.append(dict(when=when_est, nick=nick, what=what, action=True))
|
||||||
|
|
||||||
|
if formatting == 'html':
|
||||||
|
fmt1 = "<tr><td class=\"dateline\">%s</td><td class=\"nick %s\">%s</td><td class=\"chat %s\">%s</td>"
|
||||||
|
fmt2 = "<tr><td class=\"dateline\">%s</td><td colspan=\"2\">* <span class=\"nick %s\">%s</span> <span class=\"chat %s\">%s</span></td>"
|
||||||
|
print("""<html>
|
||||||
|
<head>
|
||||||
|
<title>%s</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
.nick { font-weight: bold; text-align: right; }
|
||||||
|
table { width: 100%%; }
|
||||||
|
tr > td { width: 10%%; }
|
||||||
|
tr > td+td { width: 10%%; }
|
||||||
|
tr > td+td+td { width: 80%%; }""" % filename)
|
||||||
|
for nick, color in nickcolor.items():
|
||||||
|
print(".%s { color: %s; }" % (nick, color))
|
||||||
|
print(".%s a { color: %s; font-weight: bold; }" % (nick, color))
|
||||||
|
|
||||||
|
print("""
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
""")
|
||||||
|
thisnick = ''
|
||||||
|
for line in log:
|
||||||
|
line['what'] = linkify(line['what'])
|
||||||
|
if not 'action' in line.keys():
|
||||||
|
if thisnick == line['nick']:
|
||||||
|
displaynick = u'▲'
|
||||||
|
else:
|
||||||
|
displaynick = line['nick']
|
||||||
|
print(fmt1 % (line['when'], line['nick'], displaynick, line['nick'], line['what']))
|
||||||
|
else:
|
||||||
|
print(fmt2 % (line['when'], line['nick'], line['nick'], line['nick'], line['what']))
|
||||||
|
|
||||||
|
thisnick = line['nick']
|
||||||
|
print("""
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>""")
|
||||||
|
else:
|
||||||
|
fmt = "%%s | %%%ds | %%s" % (max_nick)
|
||||||
|
for line in log:
|
||||||
|
if not 'action' in line.keys():
|
||||||
|
print(fmt % (line['when'], line['nick'], line['what']))
|
||||||
|
else:
|
||||||
|
print("%s | * %s %s" % (line['when'], line['nick'], line['what']))
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
;FFMETADATA1
|
||||||
|
major_brand=isom
|
||||||
|
minor_version=512
|
||||||
|
compatible_brands=isomiso2avc1mp41
|
||||||
|
encoder=Lavf57.41.100
|
||||||
|
|
||||||
|
title=Handmade Hero Day 317 - Alpha Blending Multiple Render Targets
|
||||||
|
|
||||||
|
[CHAPTER]
|
||||||
|
TIMEBASE=1/1
|
||||||
|
START=0
|
||||||
|
END=66
|
||||||
|
title=Start
|
||||||
|
|
||||||
|
[CHAPTER]
|
||||||
|
TIMEBASE=1/1
|
||||||
|
START=66
|
||||||
|
END=176
|
||||||
|
title=Run the game and show our current situation with render targets
|
||||||
|
|
||||||
|
[CHAPTER]
|
||||||
|
TIMEBASE=1/1
|
||||||
|
START=176
|
||||||
|
END=368
|
||||||
|
title=handmade_entity.cpp: Make UpdateAndRenderEntities() create two different ClipRects for the alpha and normal floors
|
||||||
|
|
||||||
|
[CHAPTER]
|
||||||
|
TIMEBASE=1/1
|
||||||
|
START=368
|
||||||
|
END=413
|
||||||
|
title=Run the game and see that the alpha stuff is gone
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/bin/zsh
|
||||||
|
|
||||||
|
#Default settings
|
||||||
|
DLART="0"
|
||||||
|
DLPRE="0"
|
||||||
|
DLSRC="0"
|
||||||
|
DLVID="1"
|
||||||
|
RATE="800K"
|
||||||
|
|
||||||
|
# My environment settings
|
||||||
|
SRCDIR="${HOME}/Software/src/Handmade Hero" # the directory to save Casey's files
|
||||||
|
VIDDIR="${HOME}/Media/Videos/YouTube/Handmade Hero" # the direct to save the videos
|
||||||
|
OWLURL="" # the url in the email from Molly@sendowl.com
|
||||||
|
|
||||||
|
# Casey's files
|
||||||
|
HMHSRC_001_099="file?product_id=168514"
|
||||||
|
HMHSRC_100_199="file?product_id=79802"
|
||||||
|
HMHART="file?product_id=93897"
|
||||||
|
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
echo "usage: dlhmh [option]"
|
||||||
|
echo
|
||||||
|
echo " -art - disable art"
|
||||||
|
echo " +art - enable art"
|
||||||
|
echo " -pre - disable pre-stream video"
|
||||||
|
echo " +pre - enable pre-stream video"
|
||||||
|
echo " -src - disable source"
|
||||||
|
echo " +src - enable source"
|
||||||
|
echo " -vid - disable main stream"
|
||||||
|
echo " +vid - enable main stream"
|
||||||
|
echo
|
||||||
|
echo " -fs - download at full-speed"
|
||||||
|
echo " -h|--help - outputs this message"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
# Argument parsing
|
||||||
|
while [[ $1 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
'-art') DLART='0';;
|
||||||
|
'+art') DLART='1';;
|
||||||
|
'-pre') DLPRE='0';;
|
||||||
|
'+pre') DLPRE='1' ; echo "Downloading the pre-stream video is not yet implemented\nExiting..." ; exit;;
|
||||||
|
'-src') DLSRC='0';;
|
||||||
|
'+src') DLSRC='1';;
|
||||||
|
'-vid') DLVID='0';;
|
||||||
|
'+vid') DLVID='1';;
|
||||||
|
'-fs') RATE="9G";;
|
||||||
|
'-h'|'--help') usage ;;
|
||||||
|
*) echo "${0##*/}: No such option, mate!\n" ; usage ; exit 127 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Downloading the art assets
|
||||||
|
if [[ "$DLART" == "1" ]]; then
|
||||||
|
wget -O "${SRCDIR}/handmade_hero_assets.zip" "${OWLURL}/${HMHART}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Downloading the pre-stream video
|
||||||
|
if [[ "$DLPRE" == "1" ]]; then
|
||||||
|
#NOTE(matt): This is where the pre-stream downloading code will go
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Downloading the source code
|
||||||
|
if [[ "$DLSRC" == "1" ]]; then
|
||||||
|
if [[ ! -e "${SRCDIR}/handmade_hero_source_001-099.zip" ]]; then
|
||||||
|
wget -O "${SRCDIR}/handmade_hero_source_001-099.zip" "${OWLURL}/${HMHSRC_001_099}"
|
||||||
|
fi
|
||||||
|
wget -O "${SRCDIR}/handmade_hero_source_100-199.zip" "${OWLURL}/${HMHSRC_100_199}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# YouTube playlists:
|
||||||
|
# https://www.youtube.com/user/handmadeheroarchive/playlists
|
||||||
|
|
||||||
|
#youtube-dl -o "${VIDDIR}/04. Game Architecture/%(title)s-%(id)s.%(ext)s" "https://www.youtube.com/playlist?list=PLEMXAbCVnmY6v0eFYcyiH7twEh1UF2Lxw"
|
||||||
|
#youtube-dl -o "${VIDDIR}/05. Asset Pipeline/%(title)s-%(id)s.%(ext)s" "https://www.youtube.com/playlist?list=PLEMXAbCVnmY6JVkAI8elXUJ-83HY706AQ"
|
||||||
|
#youtube-dl -o "${VIDDIR}/06. Rendering/%(title)s-%(id)s.%(ext)s" "https://www.youtube.com/playlist?list=PLEMXAbCVnmY40lfaaowTqIs_dKNgOXR5Q"
|
||||||
|
|
||||||
|
# Download all of the videos from the last 4 days ago into the HMH base directory
|
||||||
|
# NOTE(matt): Maybe figure out a way to download them to playlists while still
|
||||||
|
# keeping the '4 days ago' thing
|
||||||
|
if [[ "$DLVID" == "1" ]]; then
|
||||||
|
youtube-dl -i -r $RATE -f 137+140 --download-archive "${VIDDIR}/.dlarchive" -o "${VIDDIR}/%(title)s-%(id)s.%(ext)s" --dateafter "$(date +%Y%m%d -d'8 days ago')" "https://www.youtube.com/user/handmadeheroarchive"
|
||||||
|
fi
|
|
@ -0,0 +1,39 @@
|
||||||
|
! ----------------------------------------------------------------------------
|
||||||
|
! file: ~/.Xresources-softlo
|
||||||
|
! author: Miblo - http://www.miblodelcarpio.co.uk/
|
||||||
|
! modified: 2013-11-10
|
||||||
|
! vim:fenc=utf-8:nu:ai:si:et:ts=4:sw=4:ft=xdefaults:
|
||||||
|
! ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
*background: #000000
|
||||||
|
*foreground: #FFFFFF
|
||||||
|
*fading: 40
|
||||||
|
*fadeColor: #000000
|
||||||
|
*cursorColor: #33FF33
|
||||||
|
*pointerColorBackground:#99FF33
|
||||||
|
*pointerColorForeground:#000000
|
||||||
|
|
||||||
|
!! blacks: Black / Dark grey
|
||||||
|
*color0: #000000
|
||||||
|
*color8: #3D3D3D
|
||||||
|
!! reds: Super Meat Boy red / Light brilliant red
|
||||||
|
*color1: #BA0001
|
||||||
|
*color9: #FF3333
|
||||||
|
!! greens: Light brilliant green / Light brilliant chartreuse green
|
||||||
|
*color2: #33FF33
|
||||||
|
*color10: #99FF33
|
||||||
|
!! yellows: Light brilliant orange / L—event yellow
|
||||||
|
*color3: #FF9933
|
||||||
|
*color11: #FEF697
|
||||||
|
!! blues: Light brilliant blue / Light brilliant azure
|
||||||
|
*color4: #3333FF
|
||||||
|
*color12: #3399FF
|
||||||
|
!! magentas: Light brilliant violet / Light brilliant magenta
|
||||||
|
*color5: #9933FF
|
||||||
|
*color13: #FF33FF
|
||||||
|
!! cyans: Light brilliant cyan / Very light cyan
|
||||||
|
*color6: #33FFFF
|
||||||
|
*color14: #99FFFF
|
||||||
|
!! whites: Cosmic latte / White
|
||||||
|
*color7: #FFF8E7
|
||||||
|
*color15: #FFFFFF
|
|
@ -0,0 +1,41 @@
|
||||||
|
! ----------------------------------------------------------------------------
|
||||||
|
! file: ~/.Xresources
|
||||||
|
! author: Miblo - http://www.miblodelcarpio.co.uk/
|
||||||
|
! modified: 2012-06-15
|
||||||
|
! vim:fenc=utf-8:nu:ai:si:et:ts=4:sw=4:ft=xdefaults:
|
||||||
|
! ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include ".Xresources-softlo"
|
||||||
|
|
||||||
|
Xcursor.theme: oxy-neon
|
||||||
|
|
||||||
|
XTerm*vt100.faceName: inconsolata
|
||||||
|
XTerm*vt100.faceSize: 9
|
||||||
|
|
||||||
|
URxvt*termName: rxvt-256color
|
||||||
|
!URxvt.letterSpace: -1
|
||||||
|
URxvt.font: xft:inconsolata:size=9,\
|
||||||
|
xft:Liberation Mono,\
|
||||||
|
xft:IPAPMincho,\
|
||||||
|
xft:symbola
|
||||||
|
URxvt.boldFont: xft:inconsolata:bold:size=9,\
|
||||||
|
xft:Liberation Mono,\
|
||||||
|
xft:IPAPMincho,\
|
||||||
|
xft:symbola
|
||||||
|
URxvt*externalBorder: 0
|
||||||
|
URxvt*internalBorder: 0
|
||||||
|
URxvt*saveLines: 4096
|
||||||
|
URxvt.scrollBar: false
|
||||||
|
!URxvt.tabbed.tabbar-fg: 15
|
||||||
|
!URxvt.tabbed.tabbar-bg: 0
|
||||||
|
!URxvt.tabbed.tab-fg: 15
|
||||||
|
!URxvt.tabbed.tab-bg: 4
|
||||||
|
|
||||||
|
!URxvt.perl-ext: default,clipboard,tabbed,url-select,keyboard-select
|
||||||
|
URxvt.perl-ext: default,clipboard,url-select,keyboard-select
|
||||||
|
URxvt.keysym.M-u: perl:url-select:select_next
|
||||||
|
URxvt.keysym.M-Escape: perl:keyboard-select:activate
|
||||||
|
URxvt.keysym.M-s: perl:keyboard-select:search
|
||||||
|
URxvt.url-select.launcher: firefox
|
||||||
|
URxvt.url-select.underline: true
|
||||||
|
URxvt*boldMode: false
|
|
@ -0,0 +1,477 @@
|
||||||
|
a 0 512
|
||||||
|
a 1 128
|
||||||
|
r 0 640
|
||||||
|
a 2 128
|
||||||
|
f 1
|
||||||
|
r 0 768
|
||||||
|
a 3 128
|
||||||
|
f 2
|
||||||
|
r 0 896
|
||||||
|
a 4 128
|
||||||
|
f 3
|
||||||
|
r 0 1024
|
||||||
|
a 5 128
|
||||||
|
f 4
|
||||||
|
r 0 1152
|
||||||
|
a 6 128
|
||||||
|
f 5
|
||||||
|
r 0 1280
|
||||||
|
a 7 128
|
||||||
|
f 6
|
||||||
|
r 0 1408
|
||||||
|
a 8 128
|
||||||
|
f 7
|
||||||
|
r 0 1536
|
||||||
|
a 9 128
|
||||||
|
f 8
|
||||||
|
r 0 1664
|
||||||
|
a 10 128
|
||||||
|
f 9
|
||||||
|
r 0 1792
|
||||||
|
a 11 128
|
||||||
|
f 10
|
||||||
|
r 0 1920
|
||||||
|
a 12 128
|
||||||
|
f 11
|
||||||
|
r 0 2048
|
||||||
|
a 13 128
|
||||||
|
f 12
|
||||||
|
r 0 2176
|
||||||
|
a 14 128
|
||||||
|
f 13
|
||||||
|
r 0 2304
|
||||||
|
a 15 128
|
||||||
|
f 14
|
||||||
|
r 0 2432
|
||||||
|
a 16 128
|
||||||
|
f 15
|
||||||
|
r 0 2560
|
||||||
|
a 17 128
|
||||||
|
f 16
|
||||||
|
r 0 2688
|
||||||
|
a 18 128
|
||||||
|
f 17
|
||||||
|
r 0 2816
|
||||||
|
a 19 128
|
||||||
|
f 18
|
||||||
|
r 0 2944
|
||||||
|
a 20 128
|
||||||
|
f 19
|
||||||
|
r 0 3072
|
||||||
|
a 21 128
|
||||||
|
f 20
|
||||||
|
r 0 3200
|
||||||
|
a 22 128
|
||||||
|
f 21
|
||||||
|
r 0 3328
|
||||||
|
a 23 128
|
||||||
|
f 22
|
||||||
|
r 0 3456
|
||||||
|
a 24 128
|
||||||
|
f 23
|
||||||
|
r 0 3584
|
||||||
|
a 25 128
|
||||||
|
f 24
|
||||||
|
r 0 3712
|
||||||
|
a 26 128
|
||||||
|
f 25
|
||||||
|
r 0 3840
|
||||||
|
a 27 128
|
||||||
|
f 26
|
||||||
|
r 0 3968
|
||||||
|
a 28 128
|
||||||
|
f 27
|
||||||
|
r 0 4096
|
||||||
|
a 29 128
|
||||||
|
f 28
|
||||||
|
r 0 4224
|
||||||
|
a 30 128
|
||||||
|
f 29
|
||||||
|
r 0 4352
|
||||||
|
a 31 128
|
||||||
|
f 30
|
||||||
|
r 0 4480
|
||||||
|
a 32 128
|
||||||
|
f 31
|
||||||
|
r 0 4608
|
||||||
|
a 33 128
|
||||||
|
f 32
|
||||||
|
r 0 4736
|
||||||
|
a 34 128
|
||||||
|
f 33
|
||||||
|
r 0 4864
|
||||||
|
a 35 128
|
||||||
|
f 34
|
||||||
|
r 0 4992
|
||||||
|
a 36 128
|
||||||
|
f 35
|
||||||
|
r 0 5120
|
||||||
|
a 37 128
|
||||||
|
f 36
|
||||||
|
r 0 5248
|
||||||
|
a 38 128
|
||||||
|
f 37
|
||||||
|
r 0 5376
|
||||||
|
a 39 128
|
||||||
|
f 38
|
||||||
|
r 0 5504
|
||||||
|
a 40 128
|
||||||
|
f 39
|
||||||
|
r 0 5632
|
||||||
|
a 41 128
|
||||||
|
f 40
|
||||||
|
r 0 5760
|
||||||
|
a 42 128
|
||||||
|
f 41
|
||||||
|
r 0 5888
|
||||||
|
a 43 128
|
||||||
|
f 42
|
||||||
|
r 0 6016
|
||||||
|
a 44 128
|
||||||
|
f 43
|
||||||
|
r 0 6144
|
||||||
|
a 45 128
|
||||||
|
f 44
|
||||||
|
r 0 6272
|
||||||
|
a 46 128
|
||||||
|
f 45
|
||||||
|
r 0 6400
|
||||||
|
a 47 128
|
||||||
|
f 46
|
||||||
|
r 0 6528
|
||||||
|
a 48 128
|
||||||
|
f 47
|
||||||
|
r 0 6656
|
||||||
|
a 49 128
|
||||||
|
f 48
|
||||||
|
r 0 6784
|
||||||
|
a 50 128
|
||||||
|
f 49
|
||||||
|
r 0 6912
|
||||||
|
a 51 128
|
||||||
|
f 50
|
||||||
|
r 0 7040
|
||||||
|
a 52 128
|
||||||
|
f 51
|
||||||
|
r 0 7168
|
||||||
|
a 53 128
|
||||||
|
f 52
|
||||||
|
r 0 7296
|
||||||
|
a 54 128
|
||||||
|
f 53
|
||||||
|
r 0 7424
|
||||||
|
a 55 128
|
||||||
|
f 54
|
||||||
|
r 0 7552
|
||||||
|
a 56 128
|
||||||
|
f 55
|
||||||
|
r 0 7680
|
||||||
|
a 57 128
|
||||||
|
f 56
|
||||||
|
r 0 7808
|
||||||
|
a 58 128
|
||||||
|
f 57
|
||||||
|
r 0 7936
|
||||||
|
a 59 128
|
||||||
|
f 58
|
||||||
|
r 0 8064
|
||||||
|
a 60 128
|
||||||
|
f 59
|
||||||
|
r 0 8192
|
||||||
|
a 61 128
|
||||||
|
f 60
|
||||||
|
r 0 8320
|
||||||
|
a 62 128
|
||||||
|
f 61
|
||||||
|
r 0 8448
|
||||||
|
a 63 128
|
||||||
|
f 62
|
||||||
|
r 0 8576
|
||||||
|
a 64 128
|
||||||
|
f 63
|
||||||
|
r 0 8704
|
||||||
|
a 65 128
|
||||||
|
f 64
|
||||||
|
r 0 8832
|
||||||
|
a 66 128
|
||||||
|
f 65
|
||||||
|
r 0 8960
|
||||||
|
a 67 128
|
||||||
|
f 66
|
||||||
|
r 0 9088
|
||||||
|
a 68 128
|
||||||
|
f 67
|
||||||
|
r 0 9216
|
||||||
|
a 69 128
|
||||||
|
f 68
|
||||||
|
r 0 9344
|
||||||
|
a 70 128
|
||||||
|
f 69
|
||||||
|
r 0 9472
|
||||||
|
a 71 128
|
||||||
|
f 70
|
||||||
|
r 0 9600
|
||||||
|
a 72 128
|
||||||
|
f 71
|
||||||
|
r 0 9728
|
||||||
|
a 73 128
|
||||||
|
f 72
|
||||||
|
r 0 9856
|
||||||
|
a 74 128
|
||||||
|
f 73
|
||||||
|
r 0 9984
|
||||||
|
a 75 128
|
||||||
|
f 74
|
||||||
|
r 0 10112
|
||||||
|
a 76 128
|
||||||
|
f 75
|
||||||
|
r 0 10240
|
||||||
|
a 77 128
|
||||||
|
f 76
|
||||||
|
r 0 10368
|
||||||
|
a 78 128
|
||||||
|
f 77
|
||||||
|
r 0 10496
|
||||||
|
a 79 128
|
||||||
|
f 78
|
||||||
|
r 0 10624
|
||||||
|
a 80 128
|
||||||
|
f 79
|
||||||
|
r 0 10752
|
||||||
|
a 81 128
|
||||||
|
f 80
|
||||||
|
r 0 10880
|
||||||
|
a 82 128
|
||||||
|
f 81
|
||||||
|
r 0 11008
|
||||||
|
a 83 128
|
||||||
|
f 82
|
||||||
|
r 0 11136
|
||||||
|
a 84 128
|
||||||
|
f 83
|
||||||
|
r 0 11264
|
||||||
|
a 85 128
|
||||||
|
f 84
|
||||||
|
r 0 11392
|
||||||
|
a 86 128
|
||||||
|
f 85
|
||||||
|
r 0 11520
|
||||||
|
a 87 128
|
||||||
|
f 86
|
||||||
|
r 0 11648
|
||||||
|
a 88 128
|
||||||
|
f 87
|
||||||
|
r 0 11776
|
||||||
|
a 89 128
|
||||||
|
f 88
|
||||||
|
r 0 11904
|
||||||
|
a 90 128
|
||||||
|
f 89
|
||||||
|
r 0 12032
|
||||||
|
a 91 128
|
||||||
|
f 90
|
||||||
|
r 0 12160
|
||||||
|
a 92 128
|
||||||
|
f 91
|
||||||
|
r 0 12288
|
||||||
|
a 93 128
|
||||||
|
f 92
|
||||||
|
r 0 12416
|
||||||
|
a 94 128
|
||||||
|
f 93
|
||||||
|
r 0 12544
|
||||||
|
a 95 128
|
||||||
|
f 94
|
||||||
|
r 0 12672
|
||||||
|
a 96 128
|
||||||
|
f 95
|
||||||
|
r 0 12800
|
||||||
|
a 97 128
|
||||||
|
f 96
|
||||||
|
r 0 12928
|
||||||
|
a 98 128
|
||||||
|
f 97
|
||||||
|
r 0 13056
|
||||||
|
a 99 128
|
||||||
|
f 98
|
||||||
|
r 0 13184
|
||||||
|
a 100 128
|
||||||
|
f 99
|
||||||
|
r 0 13312
|
||||||
|
a 101 128
|
||||||
|
f 100
|
||||||
|
r 0 13440
|
||||||
|
a 102 128
|
||||||
|
f 101
|
||||||
|
r 0 13568
|
||||||
|
a 103 128
|
||||||
|
f 102
|
||||||
|
r 0 13696
|
||||||
|
a 104 128
|
||||||
|
f 103
|
||||||
|
r 0 13824
|
||||||
|
a 105 128
|
||||||
|
f 104
|
||||||
|
r 0 13952
|
||||||
|
a 106 128
|
||||||
|
f 105
|
||||||
|
r 0 14080
|
||||||
|
a 107 128
|
||||||
|
f 106
|
||||||
|
r 0 14208
|
||||||
|
a 108 128
|
||||||
|
f 107
|
||||||
|
r 0 14336
|
||||||
|
a 109 128
|
||||||
|
f 108
|
||||||
|
r 0 14464
|
||||||
|
a 110 128
|
||||||
|
f 109
|
||||||
|
r 0 14592
|
||||||
|
a 111 128
|
||||||
|
f 110
|
||||||
|
r 0 14720
|
||||||
|
a 112 128
|
||||||
|
f 111
|
||||||
|
r 0 14848
|
||||||
|
a 113 128
|
||||||
|
f 112
|
||||||
|
r 0 14976
|
||||||
|
a 114 128
|
||||||
|
f 113
|
||||||
|
r 0 15104
|
||||||
|
a 115 128
|
||||||
|
f 114
|
||||||
|
r 0 15232
|
||||||
|
a 116 128
|
||||||
|
f 115
|
||||||
|
r 0 15360
|
||||||
|
a 117 128
|
||||||
|
f 116
|
||||||
|
r 0 15488
|
||||||
|
a 118 128
|
||||||
|
f 117
|
||||||
|
r 0 15616
|
||||||
|
a 119 128
|
||||||
|
f 118
|
||||||
|
r 0 15744
|
||||||
|
a 120 128
|
||||||
|
f 119
|
||||||
|
r 0 15872
|
||||||
|
a 121 128
|
||||||
|
f 120
|
||||||
|
r 0 16000
|
||||||
|
a 122 128
|
||||||
|
f 121
|
||||||
|
r 0 16128
|
||||||
|
a 123 128
|
||||||
|
f 122
|
||||||
|
r 0 16256
|
||||||
|
a 124 128
|
||||||
|
f 123
|
||||||
|
r 0 16384
|
||||||
|
a 125 128
|
||||||
|
f 124
|
||||||
|
r 0 16512
|
||||||
|
a 126 128
|
||||||
|
f 125
|
||||||
|
r 0 16640
|
||||||
|
a 127 128
|
||||||
|
f 126
|
||||||
|
r 0 16768
|
||||||
|
a 128 128
|
||||||
|
f 127
|
||||||
|
r 0 16896
|
||||||
|
a 129 128
|
||||||
|
f 128
|
||||||
|
r 0 17024
|
||||||
|
a 130 128
|
||||||
|
f 129
|
||||||
|
r 0 17152
|
||||||
|
a 131 128
|
||||||
|
f 130
|
||||||
|
r 0 17280
|
||||||
|
a 132 128
|
||||||
|
f 131
|
||||||
|
r 0 17408
|
||||||
|
a 133 128
|
||||||
|
f 132
|
||||||
|
r 0 17536
|
||||||
|
a 134 128
|
||||||
|
f 133
|
||||||
|
r 0 17664
|
||||||
|
a 135 128
|
||||||
|
f 134
|
||||||
|
r 0 17792
|
||||||
|
a 136 128
|
||||||
|
f 135
|
||||||
|
r 0 17920
|
||||||
|
a 137 128
|
||||||
|
f 136
|
||||||
|
r 0 18048
|
||||||
|
a 138 128
|
||||||
|
f 137
|
||||||
|
r 0 18176
|
||||||
|
a 139 128
|
||||||
|
f 138
|
||||||
|
r 0 18304
|
||||||
|
a 140 128
|
||||||
|
f 139
|
||||||
|
r 0 18432
|
||||||
|
a 141 128
|
||||||
|
f 140
|
||||||
|
r 0 18560
|
||||||
|
a 142 128
|
||||||
|
f 141
|
||||||
|
r 0 18688
|
||||||
|
a 143 128
|
||||||
|
f 142
|
||||||
|
r 0 18816
|
||||||
|
a 144 128
|
||||||
|
f 143
|
||||||
|
r 0 18944
|
||||||
|
a 145 128
|
||||||
|
f 144
|
||||||
|
r 0 19072
|
||||||
|
a 146 128
|
||||||
|
f 145
|
||||||
|
r 0 19200
|
||||||
|
a 147 128
|
||||||
|
f 146
|
||||||
|
r 0 19328
|
||||||
|
a 148 128
|
||||||
|
f 147
|
||||||
|
r 0 19456
|
||||||
|
a 149 128
|
||||||
|
f 148
|
||||||
|
r 0 19584
|
||||||
|
a 150 128
|
||||||
|
f 149
|
||||||
|
r 0 19712
|
||||||
|
a 151 128
|
||||||
|
f 150
|
||||||
|
r 0 19840
|
||||||
|
a 152 128
|
||||||
|
f 151
|
||||||
|
r 0 19968
|
||||||
|
a 153 128
|
||||||
|
f 152
|
||||||
|
r 0 20096
|
||||||
|
a 154 128
|
||||||
|
f 153
|
||||||
|
r 0 20224
|
||||||
|
a 155 128
|
||||||
|
f 154
|
||||||
|
r 0 20352
|
||||||
|
a 156 128
|
||||||
|
f 155
|
||||||
|
r 0 20480
|
||||||
|
a 157 128
|
||||||
|
f 156
|
||||||
|
r 0 20608
|
||||||
|
a 158 128
|
||||||
|
f 157
|
||||||
|
r 0 20736
|
||||||
|
a 159 128
|
||||||
|
f 158
|
||||||
|
r 0 20864
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# packs multiple images (bmp/png/...) into ico file
|
||||||
|
# width and height of images must be <= 256
|
||||||
|
# pixel format of images must be 32-bit RGBA
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import os
|
||||||
|
from PIL import Image # https://python-pillow.org/
|
||||||
|
|
||||||
|
def pack(output, inp):
|
||||||
|
count = len(inp)
|
||||||
|
|
||||||
|
with open(output, "wb") as f:
|
||||||
|
f.write(struct.pack("HHH", 0, 1, count))
|
||||||
|
offset = struct.calcsize("HHH") + struct.calcsize("BBBBHHII")*count
|
||||||
|
|
||||||
|
for i in inp:
|
||||||
|
size = os.stat(i).st_size
|
||||||
|
img = Image.open(i)
|
||||||
|
w = 0 if img.width == 256 else img.width
|
||||||
|
h = 0 if img.height == 256 else img.height
|
||||||
|
f.write(struct.pack("BBBBHHII", w, h, 0, 0, 1, 32, size, offset))
|
||||||
|
offset += size
|
||||||
|
|
||||||
|
for i in inp:
|
||||||
|
f.write(open(i, "rb").read())
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
ap = argparse.ArgumentParser(description="pack multiple images into ico file")
|
||||||
|
ap.add_argument("-o", "--out", help="output file")
|
||||||
|
ap.add_argument("input", type=str, nargs='+', help="input images")
|
||||||
|
args = ap.parse_args()
|
||||||
|
pack(args.out, args.input)
|
|
@ -0,0 +1,773 @@
|
||||||
|
// example how to set up D3D11 rendering
|
||||||
|
|
||||||
|
// set to 0 to create resizable window
|
||||||
|
#define WINDOW_WIDTH 1280
|
||||||
|
#define WINDOW_HEIGHT 720
|
||||||
|
|
||||||
|
// do you need depth buffer?
|
||||||
|
#define WINDOW_DEPTH 1
|
||||||
|
|
||||||
|
// do you need stencil buffer?
|
||||||
|
#define WINDOW_STENCIL 0
|
||||||
|
|
||||||
|
// use sRGB or MSAA for color buffer
|
||||||
|
// set 0 to disable, or 1 to enable sRGB
|
||||||
|
// typical values for MSAA are 2, 4, 8, 16, ...
|
||||||
|
// when enabled, D3D11 cannot use more modern lower-latency flip swap effect on Windows 8.1/10
|
||||||
|
// instead you can use sRGB/MSAA render target and copy it to non-sRGB window
|
||||||
|
#define WINDOW_SRGB 0
|
||||||
|
#define WINDOW_MSAA 0
|
||||||
|
|
||||||
|
// do you need vsync?
|
||||||
|
#define WINDOW_VSYNC 1
|
||||||
|
|
||||||
|
// keep this enabled when debugging
|
||||||
|
#define USE_DEBUG_MODE 1
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <d3d11_1.h>
|
||||||
|
#include <dxgi1_4.h>
|
||||||
|
#include <d3dcompiler.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#pragma comment (lib, "user32.lib")
|
||||||
|
#pragma comment (lib, "dxgi.lib")
|
||||||
|
#pragma comment (lib, "d3d11.lib")
|
||||||
|
#pragma comment (lib, "dxguid.lib")
|
||||||
|
|
||||||
|
#define SAFE_RELEASE(release, obj) if (obj) release##_Release(obj)
|
||||||
|
|
||||||
|
#define LOG_AND_RETURN_ERROR(hr, msg) do \
|
||||||
|
{ \
|
||||||
|
if (FAILED(hr)) \
|
||||||
|
{ \
|
||||||
|
LogWin32Error(hr, msg); \
|
||||||
|
return hr; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
float x, y;
|
||||||
|
float r, g, b;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct Vertex vertices[] =
|
||||||
|
{
|
||||||
|
{ 0.0f, 0.5f, 1.f, 0.f, 0.f },
|
||||||
|
{ 0.5f, -0.5f, 0.f, 1.f, 0.f },
|
||||||
|
{ -0.5f, -0.5f, 0.f, 0.f, 1.f },
|
||||||
|
};
|
||||||
|
|
||||||
|
// You can compile shader to bytecode at build time, this will increase startup
|
||||||
|
// performance and also will avoid dependency on d3dcompiler dll file.
|
||||||
|
// To do so, put the shader source in shader.hlsl file and run these two commands:
|
||||||
|
|
||||||
|
// fxc.exe /nologo /T vs_4_0_level_9_0 /E vs /O3 /WX /Zpc /Ges /Fh d3d11_vshader.h /Vn d3d11_vshader /Qstrip_reflect /Qstrip_debug /Qstrip_priv shader.hlsl
|
||||||
|
// fxc.exe /nologo /T ps_4_0_level_9_0 /E ps /O3 /WX /Zpc /Ges /Fh d3d11_pshader.h /Vn d3d11_pshader /Qstrip_reflect /Qstrip_debug /Qstrip_priv shader.hlsl
|
||||||
|
|
||||||
|
// then set next setting to 1
|
||||||
|
#define USE_PRECOMPILED_SHADERS 0
|
||||||
|
|
||||||
|
#if USE_PRECOMPILED_SHADERS
|
||||||
|
#include "d3d11_vshader.h"
|
||||||
|
#include "d3d11_pshader.h"
|
||||||
|
#else
|
||||||
|
#pragma comment (lib, "d3dcompiler.lib")
|
||||||
|
static const char d3d11_shader[] =
|
||||||
|
"struct VS_INPUT \n"
|
||||||
|
"{ \n"
|
||||||
|
" float2 pos : POSITION; \n"
|
||||||
|
" float3 col : COLOR0; \n"
|
||||||
|
"}; \n"
|
||||||
|
" \n"
|
||||||
|
"struct PS_INPUT \n"
|
||||||
|
"{ \n"
|
||||||
|
" float4 pos : SV_POSITION; \n"
|
||||||
|
" float3 col : COLOR0; \n"
|
||||||
|
"}; \n"
|
||||||
|
" \n"
|
||||||
|
"PS_INPUT vs(VS_INPUT input) \n"
|
||||||
|
"{ \n"
|
||||||
|
" PS_INPUT output; \n"
|
||||||
|
" output.pos = float4(input.pos.xy, 0.f, 1.f); \n"
|
||||||
|
" output.col = input.col; \n"
|
||||||
|
" return output; \n"
|
||||||
|
"} \n"
|
||||||
|
" \n"
|
||||||
|
"float4 ps(PS_INPUT input) : SV_Target \n"
|
||||||
|
"{ \n"
|
||||||
|
" return float4(input.col, 1.f); \n"
|
||||||
|
"} \n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// is window visible?
|
||||||
|
// if this is 0 you can skip rendering part in your code to save time
|
||||||
|
static int render_occluded;
|
||||||
|
|
||||||
|
static IDXGISwapChain* render_swapchain;
|
||||||
|
static ID3D11Device* render_device;
|
||||||
|
static ID3D11DeviceContext* render_context;
|
||||||
|
static ID3D11DeviceContext1* render_context1;
|
||||||
|
static ID3D11RenderTargetView* render_window_rtview;
|
||||||
|
#if WINDOW_DEPTH || WINDOW_STENCIL
|
||||||
|
static ID3D11DepthStencilView* render_window_dpview;
|
||||||
|
#endif
|
||||||
|
static HANDLE render_frame_latency_wait;
|
||||||
|
|
||||||
|
static ID3D11RasterizerState* render_raster_state;
|
||||||
|
static ID3D11DepthStencilState* render_depthstencil_state;
|
||||||
|
static ID3D11BlendState* render_blend_state;
|
||||||
|
static ID3D11PixelShader* render_pixel_shader;
|
||||||
|
static ID3D11VertexShader* render_vertex_shader;
|
||||||
|
static ID3D11InputLayout* render_input_layout;
|
||||||
|
static ID3D11Buffer* render_vertex_buffer;
|
||||||
|
|
||||||
|
static void LogWin32Error(DWORD err, const char* msg)
|
||||||
|
{
|
||||||
|
OutputDebugStringA(msg);
|
||||||
|
OutputDebugStringA("!\n");
|
||||||
|
|
||||||
|
LPWSTR str;
|
||||||
|
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
|
||||||
|
err, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (LPWSTR)&str, 0, NULL))
|
||||||
|
{
|
||||||
|
OutputDebugStringW(str);
|
||||||
|
LocalFree(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void LogWin32LastError(const char* msg)
|
||||||
|
{
|
||||||
|
LogWin32Error(GetLastError(), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT FatalDeviceLostError()
|
||||||
|
{
|
||||||
|
MessageBoxW(NULL, L"Cannot recreate D3D11 device, it is reset or removed!", L"Error", MB_ICONEXCLAMATION);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called when device & all d3d resources needs to be released
|
||||||
|
// can happen multiple times (e.g. after device is removed/reset)
|
||||||
|
static void RenderDestroy()
|
||||||
|
{
|
||||||
|
if (render_context)
|
||||||
|
{
|
||||||
|
ID3D11DeviceContext_ClearState(render_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_RELEASE(ID3D11Buffer, render_vertex_buffer);
|
||||||
|
SAFE_RELEASE(ID3D11InputLayout, render_input_layout);
|
||||||
|
SAFE_RELEASE(ID3D11VertexShader, render_vertex_shader);
|
||||||
|
SAFE_RELEASE(ID3D11PixelShader, render_pixel_shader);
|
||||||
|
SAFE_RELEASE(ID3D11RasterizerState, render_raster_state);
|
||||||
|
SAFE_RELEASE(ID3D11DepthStencilState, render_depthstencil_state);
|
||||||
|
SAFE_RELEASE(ID3D11BlendState, render_blend_state);
|
||||||
|
|
||||||
|
#if WINDOW_DEPTH || WINDOW_STENCIL
|
||||||
|
SAFE_RELEASE(ID3D11DepthStencilView, render_window_dpview);
|
||||||
|
#endif
|
||||||
|
SAFE_RELEASE(ID3D11RenderTargetView, render_window_rtview);
|
||||||
|
SAFE_RELEASE(ID3D11DeviceContext, render_context);
|
||||||
|
SAFE_RELEASE(ID3D11Device, render_device);
|
||||||
|
SAFE_RELEASE(IDXGISwapChain, render_swapchain);
|
||||||
|
|
||||||
|
render_context1 = NULL;
|
||||||
|
render_frame_latency_wait = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called any time device needs to be created
|
||||||
|
// can happen multiple times (e.g. after device is removed/reset)
|
||||||
|
static HRESULT RenderCreate(HWND wnd)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
D3D_FEATURE_LEVEL level;
|
||||||
|
|
||||||
|
// device, context
|
||||||
|
{
|
||||||
|
UINT flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (FAILED(hr = D3D11CreateDevice(
|
||||||
|
NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, NULL, 0, D3D11_SDK_VERSION,
|
||||||
|
&render_device, &level, &render_context)))
|
||||||
|
{
|
||||||
|
if (FAILED(hr = D3D11CreateDevice(
|
||||||
|
NULL, D3D_DRIVER_TYPE_WARP, NULL, flags, NULL, 0, D3D11_SDK_VERSION,
|
||||||
|
&render_device, &level, &render_context)))
|
||||||
|
{
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "D3D11CreateDevice failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = ID3D11DeviceContext_QueryInterface(render_context, &IID_ID3D11DeviceContext1, &render_context1);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
// using ID3D11DeviceContext1 to discard render target
|
||||||
|
ID3D11DeviceContext_Release(render_context);
|
||||||
|
render_context = (ID3D11DeviceContext*)render_context1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap chain
|
||||||
|
{
|
||||||
|
IDXGIFactory* factory;
|
||||||
|
if (FAILED(hr = CreateDXGIFactory(&IID_IDXGIFactory, &factory)))
|
||||||
|
{
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "CreateDXGIFactory failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
DXGI_SWAP_CHAIN_DESC desc =
|
||||||
|
{
|
||||||
|
.BufferDesc =
|
||||||
|
{
|
||||||
|
#if WINDOW_SRGB
|
||||||
|
.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
|
||||||
|
#else
|
||||||
|
.Format = DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||||
|
#endif
|
||||||
|
.RefreshRate =
|
||||||
|
{
|
||||||
|
.Numerator = 60,
|
||||||
|
.Denominator = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.SampleDesc =
|
||||||
|
{
|
||||||
|
#if WINDOW_MSAA
|
||||||
|
.Count = WINDOW_MSAA,
|
||||||
|
#else
|
||||||
|
.Count = 1,
|
||||||
|
#endif
|
||||||
|
.Quality = 0,
|
||||||
|
},
|
||||||
|
.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||||
|
.OutputWindow = wnd,
|
||||||
|
.Windowed = TRUE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !WINDOW_SRGB && !WINDOW_MSAA
|
||||||
|
// Windows 10 and up
|
||||||
|
desc.BufferCount = 2;
|
||||||
|
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||||
|
desc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
|
||||||
|
if (FAILED(IDXGIFactory_CreateSwapChain(factory, (IUnknown*)render_device, &desc, &render_swapchain)))
|
||||||
|
{
|
||||||
|
// Windows 8.1
|
||||||
|
desc.BufferCount = 2;
|
||||||
|
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||||
|
desc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
|
||||||
|
hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown*)render_device, &desc, &render_swapchain);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
hr = E_FAIL;
|
||||||
|
#endif
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
// older Windows
|
||||||
|
desc.BufferCount = 1;
|
||||||
|
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||||
|
desc.Flags = 0;
|
||||||
|
hr = IDXGIFactory_CreateSwapChain(factory, (IUnknown*)render_device, &desc, &render_swapchain);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "IDXGIFactory::CreateSwapChain failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
|
||||||
|
{
|
||||||
|
IDXGISwapChain2* swapchain2;
|
||||||
|
if (SUCCEEDED(hr = IDXGISwapChain_QueryInterface(render_swapchain, &IID_IDXGISwapChain2, &swapchain2)))
|
||||||
|
{
|
||||||
|
// using IDXGISwapChain2 for frame latency control
|
||||||
|
render_frame_latency_wait = IDXGISwapChain2_GetFrameLatencyWaitableObject(swapchain2);
|
||||||
|
IDXGISwapChain2_Release(swapchain2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IDXGIFactory_MakeWindowAssociation(factory, wnd, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "IDXGIFactory::MakeWindowAssociation failed");
|
||||||
|
|
||||||
|
IDXGIFactory_Release(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rasterizer state
|
||||||
|
{
|
||||||
|
D3D11_RASTERIZER_DESC desc =
|
||||||
|
{
|
||||||
|
.FillMode = D3D11_FILL_SOLID,
|
||||||
|
.CullMode = D3D11_CULL_BACK,
|
||||||
|
.FrontCounterClockwise = FALSE,
|
||||||
|
.DepthBias = 0,
|
||||||
|
.DepthBiasClamp = 0,
|
||||||
|
.SlopeScaledDepthBias = 0.f,
|
||||||
|
.DepthClipEnable = TRUE,
|
||||||
|
.ScissorEnable = FALSE,
|
||||||
|
.MultisampleEnable = WINDOW_MSAA > 0,
|
||||||
|
.AntialiasedLineEnable = FALSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreateRasterizerState(render_device, &desc, &render_raster_state);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateRasterizerState failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WINDOW_DEPTH || WINDOW_STENCIL
|
||||||
|
// depth & stencil state
|
||||||
|
{
|
||||||
|
D3D11_DEPTH_STENCIL_DESC desc =
|
||||||
|
{
|
||||||
|
.DepthEnable = WINDOW_DEPTH ? TRUE : FALSE,
|
||||||
|
.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL,
|
||||||
|
.DepthFunc = D3D11_COMPARISON_LESS,
|
||||||
|
.StencilEnable = FALSE, // if you need stencil, set up it here
|
||||||
|
.StencilReadMask = 0,
|
||||||
|
.StencilWriteMask = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreateDepthStencilState(render_device, &desc, &render_depthstencil_state);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateDepthStencilState failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// blend state
|
||||||
|
{
|
||||||
|
D3D11_BLEND_DESC desc =
|
||||||
|
{
|
||||||
|
.AlphaToCoverageEnable = FALSE,
|
||||||
|
.IndependentBlendEnable = FALSE,
|
||||||
|
.RenderTarget =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.BlendEnable = FALSE,
|
||||||
|
.SrcBlend = D3D11_BLEND_SRC_ALPHA,
|
||||||
|
.DestBlend = D3D11_BLEND_INV_SRC_ALPHA,
|
||||||
|
.BlendOp = D3D11_BLEND_OP_ADD,
|
||||||
|
.SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA,
|
||||||
|
.DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA,
|
||||||
|
.BlendOpAlpha = D3D11_BLEND_OP_ADD,
|
||||||
|
.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreateBlendState(render_device, &desc, &render_blend_state);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateBlendState failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !USE_PRECOMPILED_SHADERS
|
||||||
|
UINT shader_flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
| D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG;
|
||||||
|
#else
|
||||||
|
| D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// vertex shader & input layout
|
||||||
|
{
|
||||||
|
D3D11_INPUT_ELEMENT_DESC layout[] =
|
||||||
|
{
|
||||||
|
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(struct Vertex, x), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(struct Vertex, r), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
ID3DBlob* code = NULL;
|
||||||
|
const void* vshader;
|
||||||
|
size_t vshader_size;
|
||||||
|
|
||||||
|
#if USE_PRECOMPILED_SHADERS
|
||||||
|
vshader = d3d11_vshader;
|
||||||
|
vshader_size = sizeof(d3d11_vshader);
|
||||||
|
#else
|
||||||
|
ID3DBlob* error;
|
||||||
|
hr = D3DCompile(d3d11_shader, sizeof(d3d11_shader)-1, NULL, NULL, NULL,
|
||||||
|
"vs", "vs_4_0_level_9_0", shader_flags, 0, &code, &error);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
const void* data = ID3D10Blob_GetBufferPointer(error);
|
||||||
|
size_t size = ID3D10Blob_GetBufferSize(error);
|
||||||
|
char msg[1024];
|
||||||
|
lstrcpynA(msg, data, (int)size);
|
||||||
|
msg[size] = 0;
|
||||||
|
OutputDebugStringA(msg);
|
||||||
|
ID3D10Blob_Release(error);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "D3DCompile vs failed");
|
||||||
|
}
|
||||||
|
vshader = ID3D10Blob_GetBufferPointer(code);
|
||||||
|
vshader_size = ID3D10Blob_GetBufferSize(code);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreateVertexShader(render_device, vshader, vshader_size, NULL, &render_vertex_shader);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
SAFE_RELEASE(ID3D10Blob, code);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateVertexShader failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreateInputLayout(render_device, layout, _countof(layout),
|
||||||
|
vshader, vshader_size, &render_input_layout);
|
||||||
|
SAFE_RELEASE(ID3D10Blob, code);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateInputLayout failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// pixel shader
|
||||||
|
{
|
||||||
|
ID3DBlob* code = NULL;
|
||||||
|
const void* pshader;
|
||||||
|
size_t pshader_size;
|
||||||
|
|
||||||
|
#if USE_PRECOMPILED_SHADERS
|
||||||
|
pshader = d3d11_pshader;
|
||||||
|
pshader_size = sizeof(d3d11_pshader);
|
||||||
|
#else
|
||||||
|
ID3DBlob* error;
|
||||||
|
hr = D3DCompile(d3d11_shader, sizeof(d3d11_shader)-1, NULL, NULL, NULL,
|
||||||
|
"ps", "ps_4_0_level_9_0", shader_flags, 0, &code, &error);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
const void* data = ID3D10Blob_GetBufferPointer(error);
|
||||||
|
size_t size = ID3D10Blob_GetBufferSize(error);
|
||||||
|
char msg[1024];
|
||||||
|
lstrcpynA(msg, data, (int)size);
|
||||||
|
msg[size] = 0;
|
||||||
|
OutputDebugStringA(msg);
|
||||||
|
ID3D10Blob_Release(error);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "D3DCompile ps failed");
|
||||||
|
}
|
||||||
|
pshader = ID3D10Blob_GetBufferPointer(code);
|
||||||
|
pshader_size = ID3D10Blob_GetBufferSize(code);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreatePixelShader(render_device, pshader, pshader_size, NULL, &render_pixel_shader);
|
||||||
|
SAFE_RELEASE(ID3D10Blob, code);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreatePixelShader failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// vertex buffer
|
||||||
|
{
|
||||||
|
D3D11_BUFFER_DESC desc =
|
||||||
|
{
|
||||||
|
.ByteWidth = sizeof(vertices),
|
||||||
|
.Usage = D3D11_USAGE_IMMUTABLE,
|
||||||
|
.BindFlags = D3D11_BIND_VERTEX_BUFFER,
|
||||||
|
};
|
||||||
|
|
||||||
|
D3D11_SUBRESOURCE_DATA data =
|
||||||
|
{
|
||||||
|
.pSysMem = vertices,
|
||||||
|
};
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreateBuffer(render_device, &desc, &data, &render_vertex_buffer);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateBuffer failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called when device is reset or removed, recreate it
|
||||||
|
static HRESULT RecreateDevice(HWND wnd)
|
||||||
|
{
|
||||||
|
RenderDestroy();
|
||||||
|
HRESULT hr = RenderCreate(wnd);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
RenderDestroy();
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called when window is resized
|
||||||
|
static HRESULT RenderResize(HWND wnd, int width, int height)
|
||||||
|
{
|
||||||
|
if (width == 0 || height == 0)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (render_window_rtview)
|
||||||
|
{
|
||||||
|
ID3D11DeviceContext_OMSetRenderTargets(render_context, 0, NULL, NULL);
|
||||||
|
ID3D11RenderTargetView_Release(render_window_rtview);
|
||||||
|
render_window_rtview = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WINDOW_DEPTH || WINDOW_STENCIL
|
||||||
|
if (render_window_dpview)
|
||||||
|
{
|
||||||
|
ID3D11DepthStencilView_Release(render_window_dpview);
|
||||||
|
render_window_dpview = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UINT flags = render_frame_latency_wait ? DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT : 0;
|
||||||
|
HRESULT hr = IDXGISwapChain_ResizeBuffers(render_swapchain, 0, width, height, DXGI_FORMAT_UNKNOWN, flags);
|
||||||
|
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DRIVER_INTERNAL_ERROR)
|
||||||
|
{
|
||||||
|
if (FAILED(RecreateDevice(wnd)))
|
||||||
|
{
|
||||||
|
return FatalDeviceLostError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "IDXGISwapChain::ResizeBuffers failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11Texture2D* window_buffer;
|
||||||
|
hr = IDXGISwapChain_GetBuffer(render_swapchain, 0, &IID_ID3D11Texture2D, &window_buffer);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "IDXGISwapChain::GetBuffer failed");
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreateRenderTargetView(render_device, (ID3D11Resource*)window_buffer, NULL, &render_window_rtview);
|
||||||
|
ID3D11Texture2D_Release(window_buffer);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateRenderTargetView failed");
|
||||||
|
|
||||||
|
#if WINDOW_DEPTH || WINDOW_STENCIL
|
||||||
|
{
|
||||||
|
D3D11_TEXTURE2D_DESC desc =
|
||||||
|
{
|
||||||
|
.Width = width,
|
||||||
|
.Height = height,
|
||||||
|
.MipLevels = 1,
|
||||||
|
.ArraySize = 1,
|
||||||
|
.Format = (WINDOW_STENCIL || ID3D11Device_GetFeatureLevel(render_device) < D3D_FEATURE_LEVEL_10_0)
|
||||||
|
? DXGI_FORMAT_D24_UNORM_S8_UINT : DXGI_FORMAT_D32_FLOAT,
|
||||||
|
.SampleDesc =
|
||||||
|
{
|
||||||
|
#if WINDOW_MSAA
|
||||||
|
.Count = WINDOW_MSAA,
|
||||||
|
#else
|
||||||
|
.Count = 1,
|
||||||
|
#endif
|
||||||
|
.Quality = 0,
|
||||||
|
},
|
||||||
|
.Usage = D3D11_USAGE_DEFAULT,
|
||||||
|
.BindFlags = D3D11_BIND_DEPTH_STENCIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
ID3D11Texture2D* depth_stencil;
|
||||||
|
hr = ID3D11Device_CreateTexture2D(render_device, &desc, NULL, &depth_stencil);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateTexture2D failed");
|
||||||
|
|
||||||
|
hr = ID3D11Device_CreateDepthStencilView(render_device, (ID3D11Resource*)depth_stencil, NULL, &render_window_dpview);
|
||||||
|
ID3D11Texture2D_Release(depth_stencil);
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "ID3D11Device::CreateDepthStencilView failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
D3D11_VIEWPORT viewport =
|
||||||
|
{
|
||||||
|
.TopLeftX = 0.f,
|
||||||
|
.TopLeftY = 0.f,
|
||||||
|
.Width = (float)width,
|
||||||
|
.Height = (float)height,
|
||||||
|
.MinDepth = 0.f,
|
||||||
|
.MaxDepth = 1.f,
|
||||||
|
};
|
||||||
|
ID3D11DeviceContext_RSSetViewports(render_context, 1, &viewport);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called at end of frame
|
||||||
|
static HRESULT RenderPresent(HWND wnd)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
if (render_occluded)
|
||||||
|
{
|
||||||
|
hr = IDXGISwapChain_Present(render_swapchain, 0, DXGI_PRESENT_TEST);
|
||||||
|
if (SUCCEEDED(hr) && hr != DXGI_STATUS_OCCLUDED)
|
||||||
|
{
|
||||||
|
// DXGI window is back to normal, resuming rendering
|
||||||
|
render_occluded = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!render_occluded)
|
||||||
|
{
|
||||||
|
hr = IDXGISwapChain_Present(render_swapchain, WINDOW_VSYNC, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED)
|
||||||
|
{
|
||||||
|
if (FAILED(RecreateDevice(wnd)))
|
||||||
|
{
|
||||||
|
return FatalDeviceLostError();
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT rect;
|
||||||
|
if (!GetClientRect(wnd, &rect))
|
||||||
|
{
|
||||||
|
LogWin32LastError("GetClientRect failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RenderResize(wnd, rect.right - rect.left, rect.bottom - rect.top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (hr == DXGI_STATUS_OCCLUDED)
|
||||||
|
{
|
||||||
|
// DXGI window is occluded, skipping rendering
|
||||||
|
render_occluded = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_AND_RETURN_ERROR(hr, "IDXGISwapChain::Present failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (render_occluded)
|
||||||
|
{
|
||||||
|
Sleep(10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (render_context1)
|
||||||
|
{
|
||||||
|
ID3D11DeviceContext1_DiscardView(render_context1, (ID3D11View*)render_window_rtview);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is where rendering happens
|
||||||
|
static void RenderFrame()
|
||||||
|
{
|
||||||
|
if (!render_occluded)
|
||||||
|
{
|
||||||
|
if (render_frame_latency_wait)
|
||||||
|
{
|
||||||
|
WaitForSingleObjectEx(render_frame_latency_wait, INFINITE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WINDOW_DEPTH || WINDOW_STENCIL
|
||||||
|
ID3D11DeviceContext_OMSetRenderTargets(render_context, 1, &render_window_rtview, render_window_dpview);
|
||||||
|
ID3D11DeviceContext_OMSetDepthStencilState(render_context, render_depthstencil_state, 0);
|
||||||
|
ID3D11DeviceContext_ClearDepthStencilView(render_context, render_window_dpview, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.f, 0);
|
||||||
|
#else
|
||||||
|
ID3D11DeviceContext_OMSetRenderTargets(render_context, 1, &render_window_rtview, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clear background
|
||||||
|
FLOAT clear_color[] = { 100.f/255.f, 149.f/255.f, 237.f/255.f, 1.f };
|
||||||
|
ID3D11DeviceContext_ClearRenderTargetView(render_context, render_window_rtview, clear_color);
|
||||||
|
|
||||||
|
// draw a triangle
|
||||||
|
const UINT stride = sizeof(struct Vertex);
|
||||||
|
const UINT offset = 0;
|
||||||
|
ID3D11DeviceContext_IASetInputLayout(render_context, render_input_layout);
|
||||||
|
ID3D11DeviceContext_IASetVertexBuffers(render_context, 0, 1, &render_vertex_buffer, &stride, &offset);
|
||||||
|
ID3D11DeviceContext_IASetPrimitiveTopology(render_context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
ID3D11DeviceContext_VSSetShader(render_context, render_vertex_shader, NULL, 0);
|
||||||
|
ID3D11DeviceContext_PSSetShader(render_context, render_pixel_shader, NULL, 0);
|
||||||
|
ID3D11DeviceContext_RSSetState(render_context, render_raster_state);
|
||||||
|
ID3D11DeviceContext_OMSetBlendState(render_context, render_blend_state, NULL, ~0U);
|
||||||
|
ID3D11DeviceContext_Draw(render_context, _countof(vertices), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LRESULT CALLBACK WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||||
|
{
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_CREATE:
|
||||||
|
if (FAILED(RenderCreate(wnd)))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_DESTROY:
|
||||||
|
RenderDestroy(wnd);
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_SIZE:
|
||||||
|
if (FAILED(RenderResize(wnd, LOWORD(lparam), HIWORD(lparam))))
|
||||||
|
{
|
||||||
|
DestroyWindow(wnd);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return DefWindowProcW(wnd, msg, wparam, lparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int cmd_show)
|
||||||
|
{
|
||||||
|
WNDCLASSEXW wc =
|
||||||
|
{
|
||||||
|
.cbSize = sizeof(wc),
|
||||||
|
.lpfnWndProc = WindowProc,
|
||||||
|
.hInstance = instance,
|
||||||
|
.hIcon = LoadIconA(NULL, IDI_APPLICATION),
|
||||||
|
.hCursor = LoadCursorA(NULL, IDC_ARROW),
|
||||||
|
.lpszClassName = L"d3d11_window_class",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!RegisterClassExW(&wc))
|
||||||
|
{
|
||||||
|
LogWin32LastError("RegisterClassEx failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int width = CW_USEDEFAULT;
|
||||||
|
int height = CW_USEDEFAULT;
|
||||||
|
|
||||||
|
DWORD exstyle = WS_EX_APPWINDOW;
|
||||||
|
DWORD style = WS_OVERLAPPEDWINDOW;
|
||||||
|
|
||||||
|
if (WINDOW_WIDTH && WINDOW_HEIGHT)
|
||||||
|
{
|
||||||
|
style &= ~WS_THICKFRAME & ~WS_MAXIMIZEBOX;
|
||||||
|
|
||||||
|
RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
|
||||||
|
if (!AdjustWindowRectEx(&rect, style, FALSE, exstyle))
|
||||||
|
{
|
||||||
|
LogWin32LastError("AdjustWindowRectEx failed");
|
||||||
|
style = WS_OVERLAPPEDWINDOW;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
width = rect.right - rect.left;
|
||||||
|
height = rect.bottom - rect.top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"D3D11 Window",
|
||||||
|
style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, width, height,
|
||||||
|
NULL, NULL, wc.hInstance, NULL);
|
||||||
|
if (!wnd)
|
||||||
|
{
|
||||||
|
LogWin32LastError("CreateWindow failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
MSG msg;
|
||||||
|
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||||
|
{
|
||||||
|
if (msg.message == WM_QUIT)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessageW(&msg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderFrame();
|
||||||
|
|
||||||
|
if (FAILED(RenderPresent(wnd)))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,561 @@
|
||||||
|
// example how to set up modern OpenGL context with fallback to legacy context
|
||||||
|
|
||||||
|
// set to 0 to create resizable window
|
||||||
|
#define WINDOW_WIDTH 1280
|
||||||
|
#define WINDOW_HEIGHT 720
|
||||||
|
|
||||||
|
// do you need depth buffer?
|
||||||
|
#define WINDOW_DEPTH 1
|
||||||
|
|
||||||
|
// do you need stencil buffer?
|
||||||
|
#define WINDOW_STENCIL 0
|
||||||
|
|
||||||
|
// use sRGB for color buffer
|
||||||
|
#define WINDOW_SRGB 1
|
||||||
|
|
||||||
|
// do you need multisampling?
|
||||||
|
// to disable set to 0, to enable set to 2, 4, 8, 16, ...
|
||||||
|
#define WINDOW_MSAA 4
|
||||||
|
|
||||||
|
// do you need vsync?
|
||||||
|
#define WINDOW_VSYNC 1
|
||||||
|
|
||||||
|
// keep this enabled when debugging
|
||||||
|
#define USE_DEBUG_MODE 1
|
||||||
|
|
||||||
|
// replace this with your favorite assert() implementation
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
#include "glext.h" // download from https://www.opengl.org/registry/api/GL/glext.h
|
||||||
|
#include "wglext.h" // download from https://www.opengl.org/registry/api/GL/wglext.h
|
||||||
|
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/wgl_extensions_string.txt
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/wgl_create_context.txt
|
||||||
|
// https://www.opengl.org/registry/specs/EXT/wgl_swap_control.txt
|
||||||
|
// https://www.opengl.org/registry/specs/EXT/wgl_swap_control_tear.txt
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/framebuffer_sRGB.txt
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/multisample.txt
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/debug_output.txt
|
||||||
|
|
||||||
|
#pragma comment (lib, "gdi32.lib")
|
||||||
|
#pragma comment (lib, "user32.lib")
|
||||||
|
#pragma comment (lib, "opengl32.lib")
|
||||||
|
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
#define GL_CHECK(x) do \
|
||||||
|
{ \
|
||||||
|
x; \
|
||||||
|
GLenum err = glGetError(); \
|
||||||
|
assert(err == GL_NO_ERROR); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define GL_CHECK(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// called after context is set up (only once)
|
||||||
|
// for example, load GL extensions here & set up GL state
|
||||||
|
static void RenderInit(void)
|
||||||
|
{
|
||||||
|
GL_CHECK( glClearColor(100.f/255.f, 149.f/255.f, 237.f/255.f, 1.f) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// called before render is destroyed
|
||||||
|
static void RenderDone(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// called when window is resized
|
||||||
|
static void RenderResize(unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
GL_CHECK( glViewport(0, 0, width, height) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// called every frame before swapping buffers
|
||||||
|
static void RenderFrame(void)
|
||||||
|
{
|
||||||
|
GL_CHECK( glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) );
|
||||||
|
|
||||||
|
// use legacy GL for drawing to display a triangle
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
glColor3f(1.f, 0.f, 0.f);
|
||||||
|
glVertex2f(0.f, 0.5f);
|
||||||
|
glColor3f(0.f, 1.f, 0.f);
|
||||||
|
glVertex2f(0.5f, -0.5f);
|
||||||
|
glColor3f(0.f, 0.f, 1.f);
|
||||||
|
glVertex2f(-0.5f, -0.5f);
|
||||||
|
GL_CHECK( glEnd() );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogWin32Error(const char* msg)
|
||||||
|
{
|
||||||
|
OutputDebugStringA(msg);
|
||||||
|
OutputDebugStringA("!\n");
|
||||||
|
|
||||||
|
DWORD err = GetLastError();
|
||||||
|
|
||||||
|
LPWSTR str;
|
||||||
|
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
|
||||||
|
err, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (LPWSTR)&str, 0, NULL))
|
||||||
|
{
|
||||||
|
OutputDebugStringW(str);
|
||||||
|
LocalFree(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HGLRC CreateOldOpenGLContext(HDC dc)
|
||||||
|
{
|
||||||
|
PIXELFORMATDESCRIPTOR pfd =
|
||||||
|
{
|
||||||
|
.nSize = sizeof(pfd),
|
||||||
|
.nVersion = 1,
|
||||||
|
.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
|
||||||
|
PFD_DOUBLEBUFFER | (WINDOW_DEPTH ? 0 : PFD_DEPTH_DONTCARE),
|
||||||
|
.iPixelType = PFD_TYPE_RGBA,
|
||||||
|
.cColorBits = 24,
|
||||||
|
.cDepthBits = (WINDOW_DEPTH ? 24 : 0),
|
||||||
|
.cStencilBits = (WINDOW_STENCIL ? 8 : 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
int format = ChoosePixelFormat(dc, &pfd);
|
||||||
|
if (!format)
|
||||||
|
{
|
||||||
|
LogWin32Error("ChoosePixelFormat failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DescribePixelFormat(dc, format, sizeof(pfd), &pfd))
|
||||||
|
{
|
||||||
|
LogWin32Error("DescribePixelFormat failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetPixelFormat(dc, format, &pfd))
|
||||||
|
{
|
||||||
|
LogWin32Error("SetPixelFormat failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HGLRC rc = wglCreateContext(dc);
|
||||||
|
if (!rc)
|
||||||
|
{
|
||||||
|
LogWin32Error("wglCreateContext failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wglMakeCurrent(dc, rc))
|
||||||
|
{
|
||||||
|
LogWin32Error("wglMakeCurrent failed");
|
||||||
|
wglDeleteContext(rc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
static void APIENTRY OpenGLDebugCallback(
|
||||||
|
GLenum source, GLenum type, GLuint id, GLenum severity,
|
||||||
|
GLsizei length, const GLchar *message, const void* user)
|
||||||
|
{
|
||||||
|
OutputDebugStringA(message);
|
||||||
|
OutputDebugStringA("\n");
|
||||||
|
if (severity >= GL_DEBUG_SEVERITY_LOW_ARB && severity <= GL_DEBUG_SEVERITY_HIGH_ARB)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int StringsAreEqual(const char* src, const char* dst, size_t dstlen)
|
||||||
|
{
|
||||||
|
while (*src && dstlen-- && *dst)
|
||||||
|
{
|
||||||
|
if (*src++ != *dst++)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (dstlen && *src == *dst) || (!dstlen && *src == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HGLRC CreateOpenGLContext(HDC dc)
|
||||||
|
{
|
||||||
|
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
|
||||||
|
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
|
||||||
|
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
|
||||||
|
int wgl_ARB_multisample = 0;
|
||||||
|
int wgl_ARB_framebuffer_sRGB = 0;
|
||||||
|
int wgl_EXT_swap_control_tear = 0;
|
||||||
|
|
||||||
|
HWND wnd = CreateWindowExW(0, L"STATIC", L"Dummy Window", WS_OVERLAPPED,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
|
||||||
|
if (wnd)
|
||||||
|
{
|
||||||
|
HDC dc = GetDC(wnd);
|
||||||
|
if (dc)
|
||||||
|
{
|
||||||
|
HGLRC rc = CreateOldOpenGLContext(dc);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
|
||||||
|
(void*)wglGetProcAddress("wglGetExtensionsStringARB");
|
||||||
|
if (wglGetExtensionsStringARB != (void*)0 &&
|
||||||
|
wglGetExtensionsStringARB != (void*)1 &&
|
||||||
|
wglGetExtensionsStringARB != (void*)2 &&
|
||||||
|
wglGetExtensionsStringARB != (void*)3 &&
|
||||||
|
wglGetExtensionsStringARB != (void*)-1)
|
||||||
|
{
|
||||||
|
const char* ext = wglGetExtensionsStringARB(dc);
|
||||||
|
if (ext)
|
||||||
|
{
|
||||||
|
const char* start = ext;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while (*ext != 0 && *ext != ' ')
|
||||||
|
{
|
||||||
|
ext++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = ext - start;
|
||||||
|
if (StringsAreEqual("WGL_ARB_pixel_format", start, length))
|
||||||
|
{
|
||||||
|
wglChoosePixelFormatARB = (void*)wglGetProcAddress("wglChoosePixelFormatARB");
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("WGL_ARB_create_context", start, length))
|
||||||
|
{
|
||||||
|
wglCreateContextAttribsARB = (void*)wglGetProcAddress("wglCreateContextAttribsARB");
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("WGL_EXT_swap_control", start, length))
|
||||||
|
{
|
||||||
|
wglSwapIntervalEXT = (void*)wglGetProcAddress("wglSwapIntervalEXT");
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("WGL_ARB_framebuffer_sRGB", start, length))
|
||||||
|
{
|
||||||
|
wgl_ARB_framebuffer_sRGB = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("WGL_ARB_multisample", start, length))
|
||||||
|
{
|
||||||
|
wgl_ARB_multisample = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("WGL_ARB_framebuffer_sRGB", start, length))
|
||||||
|
{
|
||||||
|
wgl_ARB_framebuffer_sRGB = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("WGL_EXT_swap_control_tear", start, length))
|
||||||
|
{
|
||||||
|
wgl_EXT_swap_control_tear = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ext == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext++;
|
||||||
|
start = ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wglMakeCurrent(NULL, NULL);
|
||||||
|
wglDeleteContext(rc);
|
||||||
|
}
|
||||||
|
ReleaseDC(wnd, dc);
|
||||||
|
}
|
||||||
|
DestroyWindow(wnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
HGLRC rc = NULL;
|
||||||
|
|
||||||
|
if (wglCreateContextAttribsARB && wglChoosePixelFormatARB)
|
||||||
|
{
|
||||||
|
int attrib[32];
|
||||||
|
int* p = attrib;
|
||||||
|
|
||||||
|
*p++ = WGL_DRAW_TO_WINDOW_ARB; *p++ = GL_TRUE;
|
||||||
|
*p++ = WGL_ACCELERATION_ARB; *p++ = WGL_FULL_ACCELERATION_ARB;
|
||||||
|
*p++ = WGL_SUPPORT_OPENGL_ARB; *p++ = GL_TRUE;
|
||||||
|
*p++ = WGL_DOUBLE_BUFFER_ARB; *p++ = GL_TRUE;
|
||||||
|
*p++ = WGL_PIXEL_TYPE_ARB; *p++ = WGL_TYPE_RGBA_ARB;
|
||||||
|
*p++ = WGL_COLOR_BITS_ARB; *p++ = 24;
|
||||||
|
|
||||||
|
if (WINDOW_DEPTH)
|
||||||
|
{
|
||||||
|
*p++ = WGL_DEPTH_BITS_ARB;
|
||||||
|
*p++ = 24;
|
||||||
|
}
|
||||||
|
if (WINDOW_STENCIL)
|
||||||
|
{
|
||||||
|
*p++ = WGL_STENCIL_BITS_ARB;
|
||||||
|
*p++ = 8;
|
||||||
|
}
|
||||||
|
if (WINDOW_SRGB && wgl_ARB_framebuffer_sRGB)
|
||||||
|
{
|
||||||
|
*p++ = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
|
||||||
|
*p++ = GL_TRUE;
|
||||||
|
}
|
||||||
|
if (WINDOW_MSAA && wgl_ARB_multisample)
|
||||||
|
{
|
||||||
|
*p++ = WGL_SAMPLE_BUFFERS_ARB;
|
||||||
|
*p++ = 1;
|
||||||
|
*p++ = WGL_SAMPLES_ARB;
|
||||||
|
*p++ = WINDOW_MSAA;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
int format;
|
||||||
|
UINT formats;
|
||||||
|
if (!wglChoosePixelFormatARB(dc, attrib, NULL, 1, &format, &formats) || formats == 0)
|
||||||
|
{
|
||||||
|
LogWin32Error("wglChoosePixelFormatARB failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PIXELFORMATDESCRIPTOR pfd =
|
||||||
|
{
|
||||||
|
.nSize = sizeof(pfd),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!DescribePixelFormat(dc, format, sizeof(pfd), &pfd))
|
||||||
|
{
|
||||||
|
LogWin32Error("DescribePixelFormat failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!SetPixelFormat(dc, format, &pfd))
|
||||||
|
{
|
||||||
|
LogWin32Error("SetPixelFormat failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int ctx[] =
|
||||||
|
{
|
||||||
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||||
|
WGL_CONTEXT_MINOR_VERSION_ARB, 0,
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||||
|
#endif
|
||||||
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
rc = wglCreateContextAttribsARB(dc, NULL, ctx);
|
||||||
|
if (!rc)
|
||||||
|
{
|
||||||
|
LogWin32Error("wglCreateContextAttribsARB failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!wglMakeCurrent(dc, rc))
|
||||||
|
{
|
||||||
|
LogWin32Error("wglMakeCurrent failed");
|
||||||
|
wglDeleteContext(rc);
|
||||||
|
rc = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (WINDOW_MSAA && wgl_ARB_multisample)
|
||||||
|
{
|
||||||
|
GL_CHECK(glEnable(GL_MULTISAMPLE_ARB));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rc)
|
||||||
|
{
|
||||||
|
OutputDebugStringA("Failed to create modern OpenGL context, retrying with legacy context!\n");
|
||||||
|
rc = CreateOldOpenGLContext(dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
if (WINDOW_VSYNC && wglSwapIntervalEXT)
|
||||||
|
{
|
||||||
|
if (!wglSwapIntervalEXT(wgl_EXT_swap_control_tear ? -1 : 1))
|
||||||
|
{
|
||||||
|
LogWin32Error("wglSwapIntervalEXT failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
const GLubyte* ext;
|
||||||
|
GL_CHECK( ext = glGetString(GL_EXTENSIONS) );
|
||||||
|
if (ext)
|
||||||
|
{
|
||||||
|
const GLubyte* start = ext;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while (*ext != 0 && *ext != ' ')
|
||||||
|
{
|
||||||
|
ext++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = ext - start;
|
||||||
|
if (StringsAreEqual("GL_ARB_debug_output", (const char*)start, length))
|
||||||
|
{
|
||||||
|
PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB =
|
||||||
|
(void*)wglGetProcAddress("glDebugMessageCallbackARB");
|
||||||
|
GL_CHECK( glDebugMessageCallbackARB(OpenGLDebugCallback, NULL) );
|
||||||
|
GL_CHECK( glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ext == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext++;
|
||||||
|
start = ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Win32Context
|
||||||
|
{
|
||||||
|
HDC dc;
|
||||||
|
HGLRC rc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static LRESULT CALLBACK WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||||
|
{
|
||||||
|
struct Win32Context* ctx = (void*)GetWindowLongPtr(wnd, GWLP_USERDATA);
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_CREATE:
|
||||||
|
ctx = ((CREATESTRUCTW*)lparam)->lpCreateParams;
|
||||||
|
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)ctx);
|
||||||
|
|
||||||
|
if (!(ctx->dc = GetDC(wnd)))
|
||||||
|
{
|
||||||
|
LogWin32Error("GetDC failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ctx->rc = CreateOpenGLContext(ctx->dc)))
|
||||||
|
{
|
||||||
|
ReleaseDC(wnd, ctx->dc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
RenderInit();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_DESTROY:
|
||||||
|
if (ctx->rc)
|
||||||
|
{
|
||||||
|
RenderDone();
|
||||||
|
|
||||||
|
wglMakeCurrent(NULL, NULL);
|
||||||
|
wglDeleteContext(ctx->rc);
|
||||||
|
}
|
||||||
|
if (ctx->dc)
|
||||||
|
{
|
||||||
|
ReleaseDC(wnd, ctx->dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_SIZE:
|
||||||
|
RenderResize(LOWORD(lparam), HIWORD(lparam));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return DefWindowProcW(wnd, msg, wparam, lparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmd_line, int cmd_show)
|
||||||
|
{
|
||||||
|
WNDCLASSEXW wc =
|
||||||
|
{
|
||||||
|
.cbSize = sizeof(wc),
|
||||||
|
.lpfnWndProc = WindowProc,
|
||||||
|
.hInstance = instance,
|
||||||
|
.hIcon = LoadIconA(NULL, IDI_APPLICATION),
|
||||||
|
.hCursor = LoadCursorA(NULL, IDC_ARROW),
|
||||||
|
.lpszClassName = L"opengl_window_class",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!RegisterClassExW(&wc))
|
||||||
|
{
|
||||||
|
LogWin32Error("RegisterClassEx failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int width = CW_USEDEFAULT;
|
||||||
|
int height = CW_USEDEFAULT;
|
||||||
|
|
||||||
|
DWORD exstyle = WS_EX_APPWINDOW;
|
||||||
|
DWORD style = WS_OVERLAPPEDWINDOW;
|
||||||
|
|
||||||
|
if (WINDOW_WIDTH && WINDOW_HEIGHT)
|
||||||
|
{
|
||||||
|
style &= ~WS_THICKFRAME & ~WS_MAXIMIZEBOX;
|
||||||
|
|
||||||
|
RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
|
||||||
|
if (!AdjustWindowRectEx(&rect, style, FALSE, exstyle))
|
||||||
|
{
|
||||||
|
LogWin32Error("AdjustWindowRectEx failed");
|
||||||
|
style = WS_OVERLAPPEDWINDOW;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
width = rect.right - rect.left;
|
||||||
|
height = rect.bottom - rect.top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Win32Context ctx;
|
||||||
|
HWND wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"OpenGL Window",
|
||||||
|
style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, width, height,
|
||||||
|
NULL, NULL, wc.hInstance, &ctx);
|
||||||
|
if (!wnd)
|
||||||
|
{
|
||||||
|
LogWin32Error("CreateWindow failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
MSG msg;
|
||||||
|
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||||
|
{
|
||||||
|
if (msg.message == WM_QUIT)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessageW(&msg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderFrame();
|
||||||
|
|
||||||
|
if (!SwapBuffers(ctx.dc))
|
||||||
|
{
|
||||||
|
LogWin32Error("SwapBuffers failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,433 @@
|
||||||
|
// example how to set up modern OpenGL context with fallback to legacy context
|
||||||
|
// compile: gcc xlib_opengl.c -lX11 -lGL -o xlib_opengl
|
||||||
|
|
||||||
|
// set to 0 to create resizable window
|
||||||
|
#define WINDOW_WIDTH 1280
|
||||||
|
#define WINDOW_HEIGHT 720
|
||||||
|
|
||||||
|
// do you need depth buffer?
|
||||||
|
#define WINDOW_DEPTH 1
|
||||||
|
|
||||||
|
// do you need stencil buffer?
|
||||||
|
#define WINDOW_STENCIL 0
|
||||||
|
|
||||||
|
// use sRGB for color buffer
|
||||||
|
#define WINDOW_SRGB 1
|
||||||
|
|
||||||
|
// do you need multisampling?
|
||||||
|
// to disable set to 0, to enable set to 2, 4, 8, 16, ...
|
||||||
|
#define WINDOW_MSAA 4
|
||||||
|
|
||||||
|
// do you need vsync?
|
||||||
|
#define WINDOW_VSYNC 1
|
||||||
|
|
||||||
|
// keep this enabled when debugging
|
||||||
|
#define USE_DEBUG_MODE 1
|
||||||
|
|
||||||
|
// replace this with your favorite assert() implementation
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
|
||||||
|
#include "glext.h" // download from https://www.opengl.org/registry/api/GL/glext.h
|
||||||
|
#include "glxext.h" // download from https://www.opengl.org/registry/api/GL/glxext.h
|
||||||
|
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/glx_create_context.txt
|
||||||
|
// https://cgit.freedesktop.org/mesa/mesa/plain/docs/specs/MESA_swap_control.spec
|
||||||
|
// https://www.opengl.org/registry/specs/SGI/swap_control.txt
|
||||||
|
// https://www.opengl.org/registry/specs/EXT/swap_control.txt
|
||||||
|
// https://www.opengl.org/registry/specs/EXT/glx_swap_control_tear.txt
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/framebuffer_sRGB.txt
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/multisample.txt
|
||||||
|
// https://www.opengl.org/registry/specs/ARB/debug_output.txt
|
||||||
|
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
#define GL_CHECK(x) do \
|
||||||
|
{ \
|
||||||
|
x; \
|
||||||
|
GLenum err = glGetError(); \
|
||||||
|
assert(err == GL_NO_ERROR); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define GL_CHECK(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// called after context is set up (only once)
|
||||||
|
// for example, load GL extensions here & set up GL state
|
||||||
|
static void RenderInit(void)
|
||||||
|
{
|
||||||
|
GL_CHECK( glClearColor(100.f/255.f, 149.f/255.f, 237.f/255.f, 1.f) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// called before render is destroyed
|
||||||
|
static void RenderDone(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// called when window is resized
|
||||||
|
static void RenderResize(unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
GL_CHECK( glViewport(0, 0, width, height) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// called every frame before swapping buffers
|
||||||
|
static void RenderFrame(void)
|
||||||
|
{
|
||||||
|
GL_CHECK( glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) );
|
||||||
|
|
||||||
|
// use legacy GL for drawing to display a triangle
|
||||||
|
glBegin(GL_TRIANGLES);
|
||||||
|
glColor3f(1.f, 0.f, 0.f);
|
||||||
|
glVertex2f(0.f, 0.5f);
|
||||||
|
glColor3f(0.f, 1.f, 0.f);
|
||||||
|
glVertex2f(0.5f, -0.5f);
|
||||||
|
glColor3f(0.f, 0.f, 1.f);
|
||||||
|
glVertex2f(-0.5f, -0.5f);
|
||||||
|
GL_CHECK( glEnd() );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
static void APIENTRY OpenGLDebugCallback(
|
||||||
|
GLenum source, GLenum type, GLuint id, GLenum severity,
|
||||||
|
GLsizei length, const GLchar *message, const void* user)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s\n", message);
|
||||||
|
if (severity >= GL_DEBUG_SEVERITY_LOW_ARB && severity <= GL_DEBUG_SEVERITY_HIGH_ARB)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int StringsAreEqual(const char* src, const char* dst, size_t dstlen)
|
||||||
|
{
|
||||||
|
while (*src && dstlen-- && *dst)
|
||||||
|
{
|
||||||
|
if (*src++ != *dst++)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (dstlen && *src == *dst) || (!dstlen && *src == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
Display* display = XOpenDisplay(NULL);
|
||||||
|
if (!display)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "XOpenDisplay failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int glx_ARB_create_context = 0;
|
||||||
|
int glx_ARB_multisample = 0;
|
||||||
|
int glx_ARB_framebuffer_sRGB = 0;
|
||||||
|
int glx_SGI_swap_control = 0;
|
||||||
|
int glx_MESA_swap_control = 0;
|
||||||
|
int glx_EXT_swap_control = 0;
|
||||||
|
int glx_EXT_swap_control_tear = 0;
|
||||||
|
|
||||||
|
const char* glx = glXQueryExtensionsString(display, DefaultScreen(display));
|
||||||
|
if (!glx)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "glXQueryExtensionsString failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char* start = glx;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while (*glx != 0 && *glx != ' ')
|
||||||
|
{
|
||||||
|
glx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = glx - start;
|
||||||
|
if (StringsAreEqual("GLX_ARB_create_context", start, length))
|
||||||
|
{
|
||||||
|
glx_ARB_create_context = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("GLX_ARB_multisample", start, length))
|
||||||
|
{
|
||||||
|
glx_ARB_multisample = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("GLX_ARB_framebuffer_sRGB", start, length))
|
||||||
|
{
|
||||||
|
glx_ARB_framebuffer_sRGB = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("GLX_SGI_swap_control", start, length))
|
||||||
|
{
|
||||||
|
glx_SGI_swap_control = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("GLX_MESA_swap_control", start, length))
|
||||||
|
{
|
||||||
|
glx_MESA_swap_control = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("GLX_EXT_swap_control", start, length))
|
||||||
|
{
|
||||||
|
glx_EXT_swap_control = 1;
|
||||||
|
}
|
||||||
|
else if (StringsAreEqual("GLX_EXT_swap_control_tear", start, length))
|
||||||
|
{
|
||||||
|
glx_EXT_swap_control_tear = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*glx == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
glx++;
|
||||||
|
start = glx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int attr[32];
|
||||||
|
int* p = attr;
|
||||||
|
*p++ = GLX_X_VISUAL_TYPE; *p++ = GLX_TRUE_COLOR;
|
||||||
|
*p++ = GLX_DOUBLEBUFFER; *p++ = True;
|
||||||
|
*p++ = GLX_RED_SIZE; *p++ = 8;
|
||||||
|
*p++ = GLX_GREEN_SIZE; *p++ = 8;
|
||||||
|
*p++ = GLX_BLUE_SIZE; *p++ = 8;
|
||||||
|
*p++ = GLX_DEPTH_SIZE; *p++ = WINDOW_DEPTH ? 24 : 0;
|
||||||
|
*p++ = GLX_STENCIL_SIZE; *p++ = WINDOW_STENCIL ? 8 : 0;
|
||||||
|
if (WINDOW_SRGB && glx_ARB_framebuffer_sRGB)
|
||||||
|
{
|
||||||
|
*p++ = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
|
||||||
|
*p++ = True;
|
||||||
|
}
|
||||||
|
if (WINDOW_MSAA && glx_ARB_multisample)
|
||||||
|
{
|
||||||
|
*p++ = GLX_SAMPLE_BUFFERS_ARB;
|
||||||
|
*p++ = 1;
|
||||||
|
*p++ = GLX_SAMPLES_ARB;
|
||||||
|
*p++ = WINDOW_MSAA;
|
||||||
|
}
|
||||||
|
*p++ = 0;
|
||||||
|
|
||||||
|
int count;
|
||||||
|
GLXFBConfig* config = glXChooseFBConfig(display, DefaultScreen(display), attr, &count);
|
||||||
|
if (!config || count == 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "glXChooseFBConfig failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XVisualInfo* info = glXGetVisualFromFBConfig(display, config[0]);
|
||||||
|
if (!info)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "glXGetVisualFromFBConfig failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Window root = DefaultRootWindow(display);
|
||||||
|
|
||||||
|
Colormap cmap = XCreateColormap(display, root, info->visual, AllocNone);
|
||||||
|
if (!cmap)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "XCreateColormap failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XSetWindowAttributes swa;
|
||||||
|
swa.colormap = cmap;
|
||||||
|
swa.event_mask = StructureNotifyMask;
|
||||||
|
|
||||||
|
Window window = XCreateWindow(
|
||||||
|
display, root, 0, 0,
|
||||||
|
WINDOW_WIDTH ? WINDOW_WIDTH : 800,
|
||||||
|
WINDOW_HEIGHT ? WINDOW_HEIGHT : 450,
|
||||||
|
0, info->depth, InputOutput, info->visual,
|
||||||
|
CWColormap | CWEventMask, &swa);
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "XCreateWindow failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (WINDOW_WIDTH && WINDOW_HEIGHT)
|
||||||
|
{
|
||||||
|
XSizeHints* hints = XAllocSizeHints();
|
||||||
|
if (!hints)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "XAllocSizeHints failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hints->flags |= PMinSize | PMaxSize;
|
||||||
|
hints->min_width = hints->max_width = WINDOW_WIDTH;
|
||||||
|
hints->min_height = hints->max_height = WINDOW_HEIGHT;
|
||||||
|
XSetWMNormalHints(display, window, hints);
|
||||||
|
XFree(hints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Atom WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
||||||
|
XSetWMProtocols(display, window, &WM_DELETE_WINDOW, 1);
|
||||||
|
|
||||||
|
XStoreName(display, window, "OpenGL window");
|
||||||
|
XMapWindow(display, window);
|
||||||
|
|
||||||
|
GLXContext ctx = NULL;
|
||||||
|
if (glx_ARB_create_context)
|
||||||
|
{
|
||||||
|
int cattr[] =
|
||||||
|
{
|
||||||
|
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||||
|
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
|
||||||
|
#endif
|
||||||
|
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||||
|
None,
|
||||||
|
};
|
||||||
|
|
||||||
|
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
|
||||||
|
(PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB(
|
||||||
|
(const GLubyte*)"glXCreateContextAttribsARB");
|
||||||
|
ctx = glXCreateContextAttribsARB(display, config[0], 0, True, cattr);
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to create modern OpenGL context, trying legacy context!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
ctx = glXCreateContext(display, info, NULL, GL_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "glXCreateContext failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!glXMakeCurrent(display, window, ctx))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "glXMakeCurrent failed!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (WINDOW_VSYNC)
|
||||||
|
{
|
||||||
|
if (glx_EXT_swap_control)
|
||||||
|
{
|
||||||
|
PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
|
||||||
|
(PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB(
|
||||||
|
(const GLubyte*)"glXSwapIntervalEXT");
|
||||||
|
glXSwapIntervalEXT(display, window, glx_EXT_swap_control_tear ? -1 : 1);
|
||||||
|
}
|
||||||
|
else if (glx_MESA_swap_control)
|
||||||
|
{
|
||||||
|
PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA =
|
||||||
|
(PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddressARB(
|
||||||
|
(const GLubyte*)"glXSwapIntervalMESA");
|
||||||
|
if (glXSwapIntervalMESA(1))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "glXSwapIntervalMESA failed!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (glx_SGI_swap_control)
|
||||||
|
{
|
||||||
|
PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI =
|
||||||
|
(PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB(
|
||||||
|
(const GLubyte*)"glXSwapIntervalSGI");
|
||||||
|
if (glXSwapIntervalSGI(1))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "glXSwapIntervalSGI failed!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_DEBUG_MODE
|
||||||
|
const GLubyte* ext;
|
||||||
|
GL_CHECK( ext = glGetString(GL_EXTENSIONS) );
|
||||||
|
if (ext)
|
||||||
|
{
|
||||||
|
const GLubyte* start = ext;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while (*ext != 0 && *ext != ' ')
|
||||||
|
{
|
||||||
|
ext++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = ext - start;
|
||||||
|
if (StringsAreEqual("GL_ARB_debug_output", (const char*)start, length))
|
||||||
|
{
|
||||||
|
PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB =
|
||||||
|
(PFNGLDEBUGMESSAGECALLBACKARBPROC)glXGetProcAddressARB((const GLubyte*)"glDebugMessageCallbackARB");
|
||||||
|
GL_CHECK( glDebugMessageCallbackARB(OpenGLDebugCallback, NULL) );
|
||||||
|
GL_CHECK( glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ext == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext++;
|
||||||
|
start = ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (WINDOW_MSAA && glx_ARB_multisample)
|
||||||
|
{
|
||||||
|
GL_CHECK( glEnable(GL_MULTISAMPLE_ARB) );
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderInit();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (XPending(display))
|
||||||
|
{
|
||||||
|
XEvent event;
|
||||||
|
XNextEvent(display, &event);
|
||||||
|
|
||||||
|
if (event.type == ConfigureNotify)
|
||||||
|
{
|
||||||
|
RenderResize(event.xconfigure.width, event.xconfigure.height);
|
||||||
|
}
|
||||||
|
else if (event.type == ClientMessage)
|
||||||
|
{
|
||||||
|
if ((Atom)event.xclient.data.l[0] == WM_DELETE_WINDOW)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderFrame();
|
||||||
|
|
||||||
|
glXSwapBuffers(display, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderDone();
|
||||||
|
|
||||||
|
glXMakeCurrent(display, None, NULL);
|
||||||
|
}
|
||||||
|
glXDestroyContext(display, ctx);
|
||||||
|
}
|
||||||
|
XDestroyWindow(display, window);
|
||||||
|
}
|
||||||
|
XFreeColormap(display, cmap);
|
||||||
|
}
|
||||||
|
XFree(info);
|
||||||
|
}
|
||||||
|
XFree(config);
|
||||||
|
}
|
||||||
|
XCloseDisplay(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue