mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Merge pull request #498 from TomHarte/DisplayBorder
Resolves border issues in fullscreen mode
This commit is contained in:
commit
badbbdf155
@ -24,13 +24,13 @@ namespace Activity {
|
||||
class Observer {
|
||||
public:
|
||||
/// Announces to the receiver that there is an LED of name @c name.
|
||||
virtual void register_led(const std::string &name) = 0;
|
||||
virtual void register_led(const std::string &name) {}
|
||||
|
||||
/// Announces to the receiver that there is a drive of name @c name.
|
||||
virtual void register_drive(const std::string &name) = 0;
|
||||
virtual void register_drive(const std::string &name) {}
|
||||
|
||||
/// Informs the receiver of the new state of the LED with name @c name.
|
||||
virtual void set_led_status(const std::string &name, bool lit) = 0;
|
||||
virtual void set_led_status(const std::string &name, bool lit) {}
|
||||
|
||||
enum class DriveEvent {
|
||||
StepNormal,
|
||||
@ -39,11 +39,10 @@ class Observer {
|
||||
};
|
||||
|
||||
/// Informs the receiver that the named event just occurred for the drive with name @c name.
|
||||
virtual void announce_drive_event(const std::string &name, DriveEvent event) = 0;
|
||||
virtual void announce_drive_event(const std::string &name, DriveEvent event) {}
|
||||
|
||||
/// Informs the receiver of the motor-on status of the drive with name @c name.
|
||||
virtual void set_drive_motor_status(const std::string &name, bool is_on) = 0;
|
||||
|
||||
virtual void set_drive_motor_status(const std::string &name, bool is_on) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -614,6 +614,8 @@
|
||||
4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC751B11D157E61006C31D9 /* 6522Tests.swift */; };
|
||||
4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */; };
|
||||
4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; };
|
||||
4BC891AD20F6EAB300EDE5B3 /* Rectangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC891AB20F6EAB300EDE5B3 /* Rectangle.cpp */; };
|
||||
4BC891AE20F6EAB300EDE5B3 /* Rectangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC891AB20F6EAB300EDE5B3 /* Rectangle.cpp */; };
|
||||
4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */; };
|
||||
4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; };
|
||||
4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; };
|
||||
@ -1356,6 +1358,8 @@
|
||||
4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FIRFilter.cpp; sourceTree = "<group>"; };
|
||||
4BC76E681C98E31700E6EF73 /* FIRFilter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FIRFilter.hpp; sourceTree = "<group>"; };
|
||||
4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
|
||||
4BC891AB20F6EAB300EDE5B3 /* Rectangle.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Rectangle.cpp; sourceTree = "<group>"; };
|
||||
4BC891AC20F6EAB300EDE5B3 /* Rectangle.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Rectangle.hpp; sourceTree = "<group>"; };
|
||||
4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommodoreTAP.cpp; sourceTree = "<group>"; };
|
||||
4BC91B821D1F160E00884B76 /* CommodoreTAP.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CommodoreTAP.hpp; sourceTree = "<group>"; };
|
||||
4BC9DF441D044FCA00F44158 /* ROMImages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ROMImages; path = ../../../../ROMImages; sourceTree = "<group>"; };
|
||||
@ -2896,6 +2900,7 @@
|
||||
children = (
|
||||
4B5073051DDD3B9400C48FBD /* ArrayBuilder.cpp */,
|
||||
4BBF990A1C8FBA6F0075DAFB /* CRTOpenGL.cpp */,
|
||||
4BC891AB20F6EAB300EDE5B3 /* Rectangle.cpp */,
|
||||
4BBF99081C8FBA6F0075DAFB /* TextureBuilder.cpp */,
|
||||
4BBF99121C8FBA6F0075DAFB /* TextureTarget.cpp */,
|
||||
4B5073061DDD3B9400C48FBD /* ArrayBuilder.hpp */,
|
||||
@ -2903,6 +2908,7 @@
|
||||
4BBF990B1C8FBA6F0075DAFB /* CRTOpenGL.hpp */,
|
||||
4BBF990E1C8FBA6F0075DAFB /* Flywheel.hpp */,
|
||||
4BBF990F1C8FBA6F0075DAFB /* OpenGL.hpp */,
|
||||
4BC891AC20F6EAB300EDE5B3 /* Rectangle.hpp */,
|
||||
4BBF99091C8FBA6F0075DAFB /* TextureBuilder.hpp */,
|
||||
4BBF99131C8FBA6F0075DAFB /* TextureTarget.hpp */,
|
||||
4BC3B74C1CD194CC00F86E85 /* Shaders */,
|
||||
@ -3614,6 +3620,7 @@
|
||||
4B055AD81FAE9B180060FFFF /* Video.cpp in Sources */,
|
||||
4B89452F201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||
4B894531201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||
4BC891AE20F6EAB300EDE5B3 /* Rectangle.cpp in Sources */,
|
||||
4B894539201967B4007DE474 /* Tape.cpp in Sources */,
|
||||
4B055AE51FAE9B6F0060FFFF /* IntermediateShader.cpp in Sources */,
|
||||
4B15A9FD208249BB005E6C8D /* StaticAnalyser.cpp in Sources */,
|
||||
@ -3840,6 +3847,7 @@
|
||||
4BD3A30B1EE755C800B5B501 /* Video.cpp in Sources */,
|
||||
4BBF99141C8FBA6F0075DAFB /* TextureBuilder.cpp in Sources */,
|
||||
4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */,
|
||||
4BC891AD20F6EAB300EDE5B3 /* Rectangle.cpp in Sources */,
|
||||
4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */,
|
||||
4B1497881EE4A1DA00CE2596 /* ZX80O81P.cpp in Sources */,
|
||||
4B894520201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
|
||||
|
@ -57,9 +57,6 @@ struct ActivityObserver: public Activity::Observer {
|
||||
[machine addLED:[NSString stringWithUTF8String:name.c_str()]];
|
||||
}
|
||||
|
||||
void register_drive(const std::string &name) override {
|
||||
}
|
||||
|
||||
void set_led_status(const std::string &name, bool lit) override {
|
||||
[machine.delegate machine:machine led:[NSString stringWithUTF8String:name.c_str()] didChangeToLit:lit];
|
||||
}
|
||||
@ -68,9 +65,6 @@ struct ActivityObserver: public Activity::Observer {
|
||||
[machine.delegate machine:machine ledShouldBlink:[NSString stringWithUTF8String:name.c_str()]];
|
||||
}
|
||||
|
||||
void set_drive_motor_status(const std::string &name, bool is_on) override {
|
||||
}
|
||||
|
||||
__unsafe_unretained CSMachine *machine;
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
// Copyright 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
@ -21,6 +22,9 @@
|
||||
|
||||
#include "../../Concurrency/BestEffortUpdater.hpp"
|
||||
|
||||
#include "../../Activity/Observer.hpp"
|
||||
#include "../../Outputs/CRT/Internals/Rectangle.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
struct BestEffortUpdaterDelegate: public Concurrency::BestEffortUpdater::Delegate {
|
||||
@ -31,8 +35,8 @@ struct BestEffortUpdaterDelegate: public Concurrency::BestEffortUpdater::Delegat
|
||||
Machine::DynamicMachine *machine;
|
||||
};
|
||||
|
||||
// This is set to a relatively large number for now.
|
||||
struct SpeakerDelegate: public Outputs::Speaker::Speaker::Delegate {
|
||||
// This is set to a relatively large number for now.
|
||||
static const int buffer_size = 1024;
|
||||
|
||||
void speaker_did_complete_samples(Outputs::Speaker::Speaker *speaker, const std::vector<int16_t> &buffer) override {
|
||||
@ -69,6 +73,89 @@ struct SpeakerDelegate: public Outputs::Speaker::Speaker::Delegate {
|
||||
std::vector<int16_t> audio_buffer_;
|
||||
};
|
||||
|
||||
class ActivityObserver: public Activity::Observer {
|
||||
public:
|
||||
ActivityObserver(Activity::Source *source, float aspect_ratio) {
|
||||
// Get the suorce to supply all LEDs and drives.
|
||||
source->set_activity_observer(this);
|
||||
|
||||
// The objective is to display drives on one side of the screen, other LEDs on the other. Drives
|
||||
// may or may not have LEDs and this code intends to display only those which do; so a quick
|
||||
// comparative processing of the two lists is called for.
|
||||
|
||||
// Strip the list of drives to only those which have LEDs. Thwy're the ones that'll be displayed.
|
||||
drives_.resize(std::remove_if(drives_.begin(), drives_.end(), [this](const std::string &string) {
|
||||
return std::find(leds_.begin(), leds_.end(), string) == leds_.end();
|
||||
}) - drives_.begin());
|
||||
|
||||
// Remove from the list of LEDs any which are drives. Those will be represented separately.
|
||||
leds_.resize(std::remove_if(leds_.begin(), leds_.end(), [this](const std::string &string) {
|
||||
return std::find(drives_.begin(), drives_.end(), string) != drives_.end();
|
||||
}) - leds_.begin());
|
||||
|
||||
set_aspect_ratio(aspect_ratio);
|
||||
}
|
||||
|
||||
void set_aspect_ratio(float aspect_ratio) {
|
||||
lights_.clear();
|
||||
|
||||
// Generate a bunch of LEDs for connected drives.
|
||||
const float height = 0.05f;
|
||||
const float width = height / aspect_ratio;
|
||||
const float right_x = 1.0f - 2.0f * width;
|
||||
float y = 1.0f - 2.0f * height;
|
||||
for(const auto &drive: drives_) {
|
||||
// TODO: use std::make_unique as below, if/when formally embracing C++14.
|
||||
lights_.emplace(std::make_pair(drive, std::unique_ptr<OpenGL::Rectangle>(new OpenGL::Rectangle(right_x, y, width, height))));
|
||||
y -= height * 2.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
This would generate LEDs for things other than drives; I'm declining for now
|
||||
due to the inexpressiveness of just painting a rectangle.
|
||||
|
||||
const float left_x = -1.0f + 2.0f * width;
|
||||
y = 1.0f - 2.0f * height;
|
||||
for(const auto &led: leds_) {
|
||||
lights_.emplace(std::make_pair(led, std::make_unique<OpenGL::Rectangle>(left_x, y, width, height)));
|
||||
y -= height * 2.0f;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void draw() {
|
||||
for(const auto &lit_led: lit_leds_) {
|
||||
if(blinking_leds_.find(lit_led) == blinking_leds_.end() && lights_.find(lit_led) != lights_.end())
|
||||
lights_[lit_led]->draw(0.0, 0.8, 0.0);
|
||||
}
|
||||
blinking_leds_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> leds_;
|
||||
void register_led(const std::string &name) override {
|
||||
leds_.push_back(name);
|
||||
}
|
||||
|
||||
std::vector<std::string> drives_;
|
||||
void register_drive(const std::string &name) override {
|
||||
drives_.push_back(name);
|
||||
}
|
||||
|
||||
void set_led_status(const std::string &name, bool lit) override {
|
||||
if(lit) lit_leds_.insert(name);
|
||||
else lit_leds_.erase(name);
|
||||
}
|
||||
|
||||
void announce_drive_event(const std::string &name, DriveEvent event) override {
|
||||
blinking_leds_.insert(name);
|
||||
}
|
||||
|
||||
std::map<std::string, std::unique_ptr<OpenGL::Rectangle>> lights_;
|
||||
std::set<std::string> lit_leds_;
|
||||
std::set<std::string> blinking_leds_;
|
||||
};
|
||||
|
||||
bool KeyboardKeyForSDLScancode(SDL_Keycode scancode, Inputs::Keyboard::Key &key) {
|
||||
#define BIND(x, y) case SDL_SCANCODE_##x: key = Inputs::Keyboard::Key::y; break;
|
||||
switch(scancode) {
|
||||
@ -462,6 +549,16 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If the machine offers anything for activity observation,
|
||||
create and register an activity observer.
|
||||
*/
|
||||
std::unique_ptr<ActivityObserver> activity_observer;
|
||||
Activity::Source *const activity_source = machine->activity_source();
|
||||
if(activity_source) {
|
||||
activity_observer.reset(new ActivityObserver(activity_source, 4.0f / 3.0f));
|
||||
}
|
||||
|
||||
// Run the main event loop until the OS tells us to quit.
|
||||
bool should_quit = false;
|
||||
Uint32 fullscreen_mode = 0;
|
||||
@ -479,6 +576,7 @@ int main(int argc, char *argv[]) {
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &target_framebuffer);
|
||||
machine->crt_machine()->get_crt()->set_target_framebuffer(target_framebuffer);
|
||||
SDL_GetWindowSize(window, &window_width, &window_height);
|
||||
if(activity_observer) activity_observer->set_aspect_ratio(static_cast<float>(window_width) / static_cast<float>(window_height));
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -610,6 +708,7 @@ int main(int argc, char *argv[]) {
|
||||
// Display a new frame and wait for vsync.
|
||||
updater.update();
|
||||
machine->crt_machine()->get_crt()->draw_frame(static_cast<unsigned int>(window_width), static_cast<unsigned int>(window_height), false);
|
||||
if(activity_observer) activity_observer->draw();
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
|
||||
|
@ -227,11 +227,18 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
|
||||
output_shader_program_->set_output_size(output_width, output_height, visible_area_);
|
||||
last_output_width_ = output_width;
|
||||
last_output_height_ = output_height;
|
||||
|
||||
// Configure a right gutter to crop the right-hand 2% of the display.
|
||||
right_overlay_.reset(new OpenGL::Rectangle(output_shader_program_->get_right_extent() * 0.98f, -1.0f, 1.0f, 2.0f));
|
||||
}
|
||||
output_shader_program_->bind();
|
||||
|
||||
// draw
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)array_submission.output_size / OutputVertexSize);
|
||||
|
||||
// mask off the gutter
|
||||
glDisable(GL_BLEND);
|
||||
right_overlay_->draw(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
#ifdef GL_NV_texture_barrier
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "Shaders/OutputShader.hpp"
|
||||
#include "Shaders/IntermediateShader.hpp"
|
||||
#include "Rectangle.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
@ -106,6 +107,18 @@ class OpenGLOutputBuilder {
|
||||
|
||||
float integer_coordinate_multiplier_ = 1.0f;
|
||||
|
||||
// Maintain a couple of rectangles for masking off the extreme edge of the display;
|
||||
// this is a bit of a cheat: there's some tolerance in when a sync pulse will be
|
||||
// generated. So it might be slightly later than expected. Which might cause a scan
|
||||
// that is slightly longer than expected. Which means that from then on, those scans
|
||||
// might have touched parts of the extreme edge of the display which are not rescanned.
|
||||
// Which because I've implemented persistence-of-vision as an in-buffer effect will
|
||||
// cause perpetual persistence.
|
||||
//
|
||||
// The fix: just always treat that area as invisible. This is acceptable thanks to
|
||||
// the concept of overscan. One is allowed not to display extreme ends of the image.
|
||||
std::unique_ptr<OpenGL::Rectangle> right_overlay_;
|
||||
|
||||
public:
|
||||
// These two are protected by output_mutex_.
|
||||
TextureBuilder texture_builder;
|
||||
|
74
Outputs/CRT/Internals/Rectangle.cpp
Normal file
74
Outputs/CRT/Internals/Rectangle.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
//
|
||||
// Rectangle.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 11/07/2018.
|
||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Rectangle.hpp"
|
||||
|
||||
using namespace OpenGL;
|
||||
|
||||
Rectangle::Rectangle(float x, float y, float width, float height):
|
||||
pixel_shader_(
|
||||
"#version 150\n"
|
||||
|
||||
"in vec2 position;"
|
||||
|
||||
"void main(void)"
|
||||
"{"
|
||||
"gl_Position = vec4(position, 0.0, 1.0);"
|
||||
"}",
|
||||
|
||||
"#version 150\n"
|
||||
|
||||
"uniform vec4 colour;"
|
||||
"out vec4 fragColour;"
|
||||
|
||||
"void main(void)"
|
||||
"{"
|
||||
"fragColour = colour;"
|
||||
"}"
|
||||
){
|
||||
pixel_shader_.bind();
|
||||
|
||||
glGenVertexArrays(1, &drawing_vertex_array_);
|
||||
glGenBuffers(1, &drawing_array_buffer_);
|
||||
|
||||
glBindVertexArray(drawing_vertex_array_);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_);
|
||||
|
||||
GLint position_attribute = pixel_shader_.get_attrib_location("position");
|
||||
glEnableVertexAttribArray(static_cast<GLuint>(position_attribute));
|
||||
|
||||
glVertexAttribPointer(
|
||||
(GLuint)position_attribute,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
2 * sizeof(GLfloat),
|
||||
(void *)0);
|
||||
|
||||
colour_uniform_ = pixel_shader_.get_uniform_location("colour");
|
||||
|
||||
float buffer[4*2];
|
||||
|
||||
// Store positions.
|
||||
buffer[0] = x; buffer[1] = y;
|
||||
buffer[2] = x; buffer[3] = y + height;
|
||||
buffer[4] = x + width; buffer[5] = y;
|
||||
buffer[6] = x + width; buffer[7] = y + height;
|
||||
|
||||
// Upload buffer.
|
||||
glBindBuffer(GL_ARRAY_BUFFER, drawing_array_buffer_);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
void Rectangle::draw(float red, float green, float blue) {
|
||||
pixel_shader_.bind();
|
||||
glUniform4f(colour_uniform_, red, green, blue, 1.0);
|
||||
|
||||
glBindVertexArray(drawing_vertex_array_);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
41
Outputs/CRT/Internals/Rectangle.hpp
Normal file
41
Outputs/CRT/Internals/Rectangle.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
//
|
||||
// Rectangle.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 11/07/2018.
|
||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Rectangle_hpp
|
||||
#define Rectangle_hpp
|
||||
|
||||
#include "OpenGL.hpp"
|
||||
#include "Shaders/Shader.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
/*!
|
||||
Provides a wrapper for drawing a solid, single-colour rectangle.
|
||||
*/
|
||||
class Rectangle {
|
||||
public:
|
||||
/*!
|
||||
Instantiates an instance of Rectange with the coordinates given.
|
||||
*/
|
||||
Rectangle(float x, float y, float width, float height);
|
||||
|
||||
/*!
|
||||
Draws this rectangle in the colour supplied.
|
||||
*/
|
||||
void draw(float red, float green, float blue);
|
||||
|
||||
private:
|
||||
Shader pixel_shader_;
|
||||
GLuint drawing_vertex_array_ = 0, drawing_array_buffer_ = 0;
|
||||
GLint colour_uniform_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* Rectangle_hpp */
|
@ -94,15 +94,21 @@ std::unique_ptr<OutputShader> OutputShader::make_shader(const char *fragment_met
|
||||
|
||||
void OutputShader::set_output_size(unsigned int output_width, unsigned int output_height, Outputs::CRT::Rect visible_area) {
|
||||
GLfloat outputAspectRatioMultiplier = (static_cast<float>(output_width) / static_cast<float>(output_height)) / (4.0f / 3.0f);
|
||||
|
||||
GLfloat bonusWidth = (outputAspectRatioMultiplier - 1.0f) * visible_area.size.width;
|
||||
visible_area.origin.x -= bonusWidth * 0.5f * visible_area.size.width;
|
||||
|
||||
right_extent_ = (1.0f / outputAspectRatioMultiplier) / visible_area.size.width;
|
||||
|
||||
visible_area.origin.x -= bonusWidth * 0.5f;
|
||||
visible_area.size.width *= outputAspectRatioMultiplier;
|
||||
|
||||
set_uniform("boundsOrigin", (GLfloat)visible_area.origin.x, (GLfloat)visible_area.origin.y);
|
||||
set_uniform("boundsSize", (GLfloat)visible_area.size.width, (GLfloat)visible_area.size.height);
|
||||
}
|
||||
|
||||
float OutputShader::get_right_extent() {
|
||||
return right_extent_;
|
||||
}
|
||||
|
||||
void OutputShader::set_source_texture_unit(GLenum unit) {
|
||||
set_uniform("texID", (GLint)(unit - GL_TEXTURE0));
|
||||
}
|
||||
|
@ -87,6 +87,14 @@ public:
|
||||
space, 0.5 means use half, etc.
|
||||
*/
|
||||
void set_input_width_scaler(float input_scaler);
|
||||
|
||||
/*!
|
||||
@returns The location, in eye coordinates, of the right edge of the output area.
|
||||
*/
|
||||
float get_right_extent();
|
||||
|
||||
private:
|
||||
float right_extent_ = 0.0f;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ class TextureTarget {
|
||||
/*!
|
||||
Draws this texture to the currently-bound framebuffer, which has the aspect ratio
|
||||
@c aspect_ratio. This texture will fill the height of the frame buffer, and pick
|
||||
an appropriate width based o the aspect ratio.
|
||||
an appropriate width based on the aspect ratio.
|
||||
|
||||
@c colour_threshold sets a threshold test that each colour must satisfy to be
|
||||
output. A threshold of 0.0f means that all colours will pass through. A threshold
|
||||
|
Loading…
Reference in New Issue
Block a user